bookmark system rewrite. thanks to dave haas and simon woodside (bug 212630)

This commit is contained in:
pinkerton%netscape.com 2003-10-22 01:08:55 +00:00
Родитель fdee22de07
Коммит 8e313f3459
80 изменённых файлов: 9711 добавлений и 1128 удалений

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Двоичные данные
camino/resources/images/toolbar/addressbook_icon.tif Normal file

Двоичный файл не отображается.

Двоичные данные
camino/resources/images/toolbar/bookmarkmenu_icon.tif Normal file

Двоичный файл не отображается.

Двоичные данные
camino/resources/images/toolbar/bookmarktoolbar_icon.tif Normal file

Двоичный файл не отображается.

Двоичные данные
camino/resources/images/toolbar/brokenbookmark_icon.tif Normal file

Двоичный файл не отображается.

Двоичные данные
camino/resources/images/toolbar/delete_on.tif

Двоичный файл не отображается.

Двоичные данные
camino/resources/images/toolbar/info_on.tif Executable file

Двоичный файл не отображается.

Двоичные данные
camino/resources/images/toolbar/rendezvous_icon.tif Normal file

Двоичный файл не отображается.

Двоичные данные
camino/resources/images/toolbar/separator_on.tif

Двоичный файл не отображается.

Двоичные данные
camino/resources/images/toolbar/top10_icon.tif Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,17 @@
{
IBClasses = (
{
ACTIONS = {cancel = id; import = id; loadOpenPanel = id; };
CLASS = BookmarkImportDlgController;
LANGUAGE = ObjC;
OUTLETS = {
mBrowserListButton = NSPopUpButton;
mCancelButton = NSButton;
mImportButton = NSButton;
};
SUPERCLASS = NSWindowController;
},
{CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }
);
IBVersion = 1;
}

20
camino/resources/localized/English.lproj/BookmarkImportDlg.nib/info.nib сгенерированный Normal file
Просмотреть файл

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IBDocumentLocation</key>
<string>40 351 356 240 0 0 1152 746 </string>
<key>IBFramework Version</key>
<string>291.0</string>
<key>IBLockedObjects</key>
<array>
<integer>5</integer>
</array>
<key>IBOpenObjects</key>
<array>
<integer>5</integer>
</array>
<key>IBSystem Version</key>
<string>6L60</string>
</dict>
</plist>

Двоичные данные
camino/resources/localized/English.lproj/BookmarkImportDlg.nib/objects.nib сгенерированный Executable file

Двоичный файл не отображается.

Просмотреть файл

@ -1,25 +1,32 @@
{
IBClasses = (
{
ACTIONS = {dockMenuCheckboxClicked = id; tabGroupCheckboxClicked = id; };
ACTIONS = {
clearVisitCount = id;
dockMenuCheckboxClicked = id;
tabGroupCheckboxClicked = id;
};
CLASS = BookmarkInfoController;
LANGUAGE = ObjC;
OUTLETS = {
mDescriptionField = NSTextField;
mDescriptionLabel = NSTextField;
mBookmarkDescField = NSTextField;
mBookmarkKeywordField = NSTextField;
mBookmarkLocationField = NSTextField;
mBookmarkNameField = NSTextField;
mClearNumberVisitsButton = NSButton;
mDockMenuCheckbox = NSButton;
mKeywordField = NSTextField;
mKeywordLabel = NSTextField;
mLocationField = NSTextField;
mLocationLabel = NSTextField;
mNameField = NSTextField;
mNameLabel = NSTextField;
mFolderDescField = NSTextField;
mFolderKeywordField = NSTextField;
mFolderKeywordLabel = NSTextField;
mFolderNameField = NSTextField;
mLastVisitField = NSTextField;
mNumberVisitsField = NSTextField;
mStatusField = NSTextField;
mTabView = NSTabView;
mTabgroupCheckbox = NSButton;
mVariableFieldsContainer = NSView;
};
SUPERCLASS = NSWindowController;
},
{CLASS = BookmarkItem; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
{CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }
);
IBVersion = 1;

Просмотреть файл

@ -3,10 +3,51 @@
<plist version="1.0">
<dict>
<key>IBDocumentLocation</key>
<string>97 65 366 258 0 0 1600 1002 </string>
<string>9 7 466 409 0 0 1280 1002 </string>
<key>IBFramework Version</key>
<string>286.0</string>
<string>283.0</string>
<key>IBGroupedObjects</key>
<dict>
<key>13</key>
<array>
<string>224</string>
<string>225</string>
</array>
<key>14</key>
<array>
<string>291</string>
<string>292</string>
</array>
<key>16</key>
<array>
<string>296</string>
<string>301</string>
<string>302</string>
</array>
<key>17</key>
<array>
<string>295</string>
<string>298</string>
<string>299</string>
</array>
<key>18</key>
<array>
<string>280</string>
<string>281</string>
<string>282</string>
</array>
</dict>
<key>IBLastGroupID</key>
<string>19</string>
<key>IBLockedObjects</key>
<array>
<integer>130</integer>
</array>
<key>IBOpenObjects</key>
<array>
<integer>130</integer>
</array>
<key>IBSystem Version</key>
<string>6F21</string>
<string>6L60</string>
</dict>
</plist>

Двоичные данные
camino/resources/localized/English.lproj/BookmarkInfoPanel.nib/objects.nib сгенерированный

Двоичный файл не отображается.

Просмотреть файл

@ -8,56 +8,53 @@
OUTLETS = {mProxyIcon = PageProxyIcon; };
SUPERCLASS = NSTextField;
},
{CLASS = BookmarkItem; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
{CLASS = BookmarkManagerView; LANGUAGE = ObjC; SUPERCLASS = NSView; },
{
ACTIONS = {changeContainer = id; };
CLASS = BookmarksController;
LANGUAGE = ObjC;
OUTLETS = {
mAddFolderButton = NSButton;
mAddItemButton = NSButton;
mBookmarksSource = BookmarksDataSource;
mContainerPane = NSTableView;
mContainersSplit = NSSplitView;
mHistorySource = HistoryDataSource;
mInfoButton = NSButton;
mItemPane = ExtendedOutlineView;
mItemSearchSplit = NSSplitView;
mSearchPane = NSTableView;
};
SUPERCLASS = NSObject;
},
{
ACTIONS = {
addBookmark = id;
addFolder = id;
deleteBookmarks = id;
openBookmarkInNewTab = id;
openBookmarkInNewWindow = id;
showBookmarkInfo = id;
};
CLASS = BookmarksDataSource;
LANGUAGE = ObjC;
OUTLETS = {
mBrowserWindowController = id;
mDeleteBookmarkButton = id;
mEditBookmarkButton = id;
mOutlineView = id;
};
SUPERCLASS = NSObject;
},
{
CLASS = BookmarksOutlineView;
CLASS = BookmarkOutlineView;
LANGUAGE = ObjC;
SUPERCLASS = ExtendedOutlineView;
},
{
ACTIONS = {addFolder = id; };
CLASS = BookmarksToolbar;
CLASS = BookmarkToolbar;
LANGUAGE = ObjC;
SUPERCLASS = NSView;
},
{
ACTIONS = {
addBookmark = id;
addCollection = id;
addFolder = id;
addSeparator = id;
deleteBookmarks = id;
locateBookmark = id;
openBookmark = id;
openBookmarkInNewTab = id;
openBookmarkInNewWindow = id;
setAsDockMenuFolder = id;
showBookmarkInfo = id;
startSearch = id;
};
CLASS = BookmarkViewController;
LANGUAGE = ObjC;
OUTLETS = {
mAddBookmarkButton = NSButton;
mAddCollectionButton = NSButton;
mAddFolderButton = NSButton;
mAddSeparatorButton = NSButton;
mBrowserWindowController = BrowserWindowController;
mContainerPane = ExtendedTableView;
mContainersSplit = NSSplitView;
mHistorySource = HistoryDataSource;
mInfoButton = NSButton;
mItemPane = BookmarkOutlineView;
mItemSearchSplit = NSSplitView;
mSearchButton = NSButton;
mSearchField = NSTextField;
mSearchPane = NSTableView;
};
SUPERCLASS = NSObject;
},
{CLASS = BrowserContainerView; LANGUAGE = ObjC; SUPERCLASS = NSView; },
{
ACTIONS = {toggleBookmarkManager = id; };
@ -65,7 +62,7 @@
LANGUAGE = ObjC;
OUTLETS = {
mBookmarkManagerView = NSView;
mBookmarksToolbar = BookmarksToolbar;
mBookmarksToolbar = BookmarkToolbar;
mBrowserContainerView = NSView;
mStatusBar = NSView;
};
@ -142,7 +139,7 @@
mAddBookmarkSheetWindow = NSWindow;
mAddBookmarkTitleField = NSTextField;
mBackItem = NSMenuItem;
mBookmarksController = BookmarksController;
mBookmarkViewController = BookmarkViewController;
mContentView = BrowserContentView;
mCopyItem = NSMenuItem;
mForwardItem = NSMenuItem;
@ -156,17 +153,13 @@
mLocationToolbarView = NSView;
mLock = NSImageView;
mPageMenu = NSMenu;
mPersonalToolbar = BookmarksToolbar;
mPersonalToolbar = BookmarkToolbar;
mPopupBlocked = NSButton;
mProgress = NSProgressIndicator;
mProxyIcon = PageProxyIcon;
mSearchBar = SearchTextField;
mSearchSheetTextField = SearchTextField;
mSearchSheetWindow = NSWindow;
mSidebarBookmarksDataSource = BookmarksDataSource;
mSidebarDrawer = NSDrawer;
mSidebarSourceTabView = NSTabView;
mSidebarTabView = NSTabView;
mStatus = NSTextField;
mStatusBar = NSView;
mTabBrowser = BrowserTabView;
@ -176,35 +169,92 @@
SUPERCLASS = NSWindowController;
},
{
ACTIONS = {load = id; };
ACTIONS = {load = id; reloadWithNewCharset = id; };
CLASS = BrowserWrapper;
LANGUAGE = ObjC;
OUTLETS = {
mLockIcon = id;
mWindowController = id;
progress = id;
progressSuper = id;
status = id;
urlbar = id;
};
SUPERCLASS = NSView;
},
{CLASS = ExtendedOutlineView; LANGUAGE = ObjC; SUPERCLASS = NSOutlineView; },
{CLASS = ExtendedTableView; LANGUAGE = ObjC; SUPERCLASS = NSTableView; },
{CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
{
ACTIONS = {deleteHistoryItems = id; openHistoryItem = id; };
CLASS = HistoryDataSource;
LANGUAGE = ObjC;
OUTLETS = {mBrowserWindowController = id; };
OUTLETS = {mBrowserWindowController = BrowserWindowController; };
SUPERCLASS = RDFOutlineViewDataSource;
},
{CLASS = LocationBar; LANGUAGE = ObjC; SUPERCLASS = NSView; },
{CLASS = MainController; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
{
ACTIONS = {
aboutServers = id;
addBookmark = id;
addFolder = id;
addSeparator = id;
biggerTextSize = id;
closeTab = id;
connectToServer = id;
displayPreferencesWindow = id;
doReload = id;
doSearch = id;
doStop = id;
downloadsWindow = id;
exportBookmarks = id;
feedbackLink = id;
findAgain = id;
findInPage = id;
findPrevious = id;
getInfo = id;
goBack = id;
goForward = id;
goHome = id;
importBookmarks = id;
infoLink = id;
manageSidebar = id;
newTab = id;
newWindow = id;
nextTab = id;
openFile = id;
openLocation = id;
openMenuBookmark = id;
pageSetup = id;
previousTab = id;
printPage = id;
reloadWithCharset = id;
savePage = id;
sendURL = id;
showAboutBox = id;
smallerTextSize = id;
toggleBookmarksToolbar = id;
toggleOfflineMode = id;
toggleSidebar = id;
viewSource = id;
};
CLASS = MainController;
LANGUAGE = ObjC;
OUTLETS = {
mAddBookmarkMenuItem = NSMenuItem;
mApplication = NSApplication;
mBookmarksMenu = NSMenu;
mBookmarksToolbarMenuItem = NSMenuItem;
mCloseTabMenuItem = NSMenuItem;
mCloseWindowMenuItem = NSMenuItem;
mCreateBookmarksFolderMenuItem = NSMenuItem;
mCreateBookmarksSeparatorMenuItem = NSMenuItem;
mDockMenu = NSMenu;
mFilterView = NSView;
mGoMenu = NSMenu;
mServersSubmenu = NSMenu;
mToggleSidebarMenuItem = NSMenuItem;
};
SUPERCLASS = NSObject;
},
{CLASS = NSObject; LANGUAGE = ObjC; },
{CLASS = PageProxyIcon; LANGUAGE = ObjC; SUPERCLASS = NSImageView; },
{
CLASS = RDFOutlineViewDataSource;
LANGUAGE = ObjC;
OUTLETS = {mOutlineView = id; };
OUTLETS = {mOutlineView = ExtendedOutlineView; };
SUPERCLASS = NSObject;
},
{CLASS = RDFOutlineViewItem; LANGUAGE = ObjC; SUPERCLASS = NSObject; },

Просмотреть файл

@ -3,15 +3,11 @@
<plist version="1.0">
<dict>
<key>IBDocumentLocation</key>
<string>122 60 653 383 0 0 1280 832 </string>
<string>40 268 545 473 0 0 1152 746 </string>
<key>IBEditorPositions</key>
<dict>
<key>124</key>
<string>83 451 170 144 0 0 1280 832 </string>
<key>160</key>
<string>602 52 195 666 0 0 1024 746 </string>
<key>28</key>
<string>542 342 195 457 0 0 1280 832 </string>
<string>58 576 170 96 0 0 1152 746 </string>
<key>297</key>
<string>82 354 213 294 0 0 1280 832 </string>
<key>314</key>
@ -27,11 +23,13 @@
<key>654</key>
<string>159 629 198 144 0 0 1280 832 </string>
<key>731</key>
<string>185 277 654 459 0 0 1024 746 </string>
<string>249 277 654 459 0 0 1152 746 </string>
<key>801</key>
<string>418 469 201 79 0 0 1024 746 </string>
<key>826</key>
<string>84 461 213 78 0 0 1152 848 </string>
<string>84 401 213 60 0 0 1152 746 </string>
<key>894</key>
<string>276 641 156 66 0 0 1152 746 </string>
</dict>
<key>IBFramework Version</key>
<string>291.0</string>
@ -44,14 +42,18 @@
</array>
</dict>
<key>IBLastGroupID</key>
<string>8</string>
<string>10</string>
<key>IBLockedObjects</key>
<array/>
<array>
<integer>748</integer>
<integer>910</integer>
<integer>889</integer>
</array>
<key>IBOpenObjects</key>
<array>
<integer>826</integer>
<integer>731</integer>
</array>
<key>IBSystem Version</key>
<string>6L29</string>
<string>6L60</string>
</dict>
</plist>

Двоичные данные
camino/resources/localized/English.lproj/BrowserWindow.nib/objects.nib сгенерированный

Двоичный файл не отображается.

Двоичный файл не отображается.

Просмотреть файл

@ -81,7 +81,7 @@ AppDirServiceProvider::GetFile(const char *prop, PRBool *persistant, nsIFile **_
*_retval = nsnull;
*persistant = PR_TRUE;
if (strcmp(prop, NS_APP_APPLICATION_REGISTRY_DIR) == 0)
if (strcmp(prop, NS_APP_USER_PROFILE_50_DIR) == 0)
{
rv = GetProductDirectory(getter_AddRefs(localFile));
}

Просмотреть файл

@ -36,17 +36,16 @@
* ***** END LICENSE BLOCK ***** */
#import <Cocoa/Cocoa.h>
#import "BrowserWindowController.h"
#import "MVPreferencesController.h"
#import "SplashScreenWindow.h"
#import "FindDlgController.h"
#import "PreferenceManager.h"
#import "SharedMenusObj.h"
#import "NetworkServices.h"
@class BookmarksMenu;
@class BookmarkMenu;
@class BookmarkManager;
@class KeychainService;
@class NetworkServices;
@class BrowserWindowController;
@class SplashScreenWindow;
@class SharedMenusObj;
@class PreferenceManager;
@class FindDlgController;
@class MVPreferencesController;
@interface MainController : NSObject
{
@ -74,10 +73,8 @@
SplashScreenWindow* mSplashScreen;
PreferenceManager* mPreferenceManager;
BookmarksMenu* mMenuBookmarks;
BookmarksMenu* mDockBookmarks;
BookmarkMenu* mMenuBookmarks;
BookmarkMenu* mDockBookmarks;
KeychainService* mKeychainService;
@ -88,8 +85,6 @@
NSString* mStartURL;
SharedMenusObj* mSharedMenusObj;
NetworkServices* mNetworkServices;
NSMutableDictionary* mCharsets;
}
@ -161,9 +156,9 @@
- (NSView*)getSavePanelView;
- (NSWindow*)getFrontmostBrowserWindow;
- (void)setupBookmarkMenus:(BookmarkManager *)BookmarkManager;
- (MVPreferencesController *)preferencesController;
- (void)displayPreferencesWindow:sender;
- (PreferenceManager *)preferenceManager;
- (BOOL)isMainWindowABrowserWindow;
// if the main window is a browser window, return its controller, otherwise nil

Просмотреть файл

@ -43,9 +43,13 @@
#import "ChimeraUIConstants.h"
#import "MainController.h"
#import "BrowserWindowController.h"
#import "BookmarksMenu.h"
#import "BookmarksService.h"
#import "BookmarkInfoController.h";
#import "BookmarkMenu.h"
#import "Bookmark.h"
#import "BookmarkFolder.h"
#import "BookmarkInfoController.h"
#import "BookmarkManager.h"
#import "BookmarkToolbar.h"
#import "RunLoopMessenger.h"
#import "CHBrowserService.h"
#import "AboutBox.h"
#import "UserDefaults.h"
@ -54,6 +58,11 @@
#import "ProgressDlgController.h"
#import "JSConsole.h"
#import "NetworkServices.h"
#import "MVPreferencesController.h"
#import "SplashScreenWindow.h"
#import "FindDlgController.h"
#import "PreferenceManager.h"
#import "SharedMenusObj.h"
#include "nsCOMPtr.h"
#include "nsEmbedAPI.h"
@ -93,12 +102,9 @@ const int kReuseWindowOnAE = 2;
// over to doing things the right way when the time comes.
#define kFixedDockMenuAppKitVersion 632
@interface MainController(MainControllerPrivate)
@interface MainController(Private)<NetworkServicesClient>
- (void)setupStartpage;
- (void)setupNetworkBrowser;
- (void)foundService:(NSNetService*)inService moreComing:(BOOL)more;
- (void)rebuildNetServiceMenu;
@end
@ -142,7 +148,6 @@ const int kReuseWindowOnAE = 2;
mMenuBookmarks = nil;
[NSApp setServicesProvider:self];
// Initialize shared menu support
mSharedMenusObj = [[SharedMenusObj alloc] init];
}
@ -169,10 +174,14 @@ const int kReuseWindowOnAE = 2;
#ifdef _BUILD_STATIC_BIN
[self updatePrebinding];
#endif
// initialize if we haven't already.
[self preferenceManager];
PreferenceManager *pm = [PreferenceManager sharedInstance];
// start bookmarks
RunLoopMessenger *mainThreadRunLoopMessenger = [[RunLoopMessenger alloc] init];
[NSThread detachNewThreadSelector:@selector(startBookmarksManager:) toTarget:[BookmarkManager class] withObject:mainThreadRunLoopMessenger];
[mainThreadRunLoopMessenger release]; //bookmark manager retains this
[self setupStartpage];
// register our app components with the embed layer
@ -180,46 +189,15 @@ const int kReuseWindowOnAE = 2;
const nsModuleComponentInfo* comps = GetAppComponents(&numComps);
CHBrowserService::RegisterAppComponents(comps, numComps);
// make sure we have a bookmarks manager
BookmarksManager* bmManager = [BookmarksManager sharedBookmarksManager];
// don't open a new browser window if we already have one
// (for example, from an GetURL Apple Event)
NSWindow* browserWindow = [self getFrontmostBrowserWindow];
if (!browserWindow)
[self newWindow: self];
[mSplashScreen close];
[mSplashScreen close]; //deallocs on close
mSplashScreen = nil;
[mBookmarksMenu setAutoenablesItems: NO];
// menubar bookmarks
int firstBookmarkItem = [mBookmarksMenu indexOfItemWithTag:kBookmarksDividerTag] + 1;
mMenuBookmarks = [[BookmarksMenu alloc] initWithMenu: mBookmarksMenu
firstItem: firstBookmarkItem
rootContent: [bmManager getRootContent]
watchedFolder: eBookmarksFolderRoot];
[bmManager addBookmarksClient:mMenuBookmarks];
// dock bookmarks. Note that we disable them on 10.1 because of a bug noted here:
// http://developer.apple.com/samplecode/Sample_Code/Cocoa/DeskPictAppDockMenu.htm
if (NSAppKitVersionNumber >= kFixedDockMenuAppKitVersion)
{
[mDockMenu setAutoenablesItems:NO];
int firstBookmarkItem = [mDockMenu indexOfItemWithTag:kBookmarksDividerTag] + 1;
mDockBookmarks = [[BookmarksMenu alloc] initWithMenu: mDockMenu
firstItem: firstBookmarkItem
rootContent: [bmManager getDockMenuRoot]
watchedFolder: eBookmarksFolderDockMenu];
[bmManager addBookmarksClient:mDockBookmarks];
}
else
{
// just empty the menu
while ([mDockMenu numberOfItems] > 0)
[mDockMenu removeItemAtIndex:0];
}
// Initialize offline mode.
mOffline = NO;
nsCOMPtr<nsIIOService> ioService(do_GetService(ioServiceContractID));
@ -228,27 +206,28 @@ const int kReuseWindowOnAE = 2;
PRBool offline = PR_FALSE;
ioService->GetOffline(&offline);
mOffline = offline;
// Initialize the keychain service.
mKeychainService = [KeychainService instance];
// bring up the JS console service
BOOL success;
if ([[PreferenceManager sharedInstance] getBooleanPref:"chimera.log_js_to_console" withSuccess:&success])
if ([pm getBooleanPref:"chimera.log_js_to_console" withSuccess:&success])
[JSConsole sharedJSConsole];
BOOL doingRendezvous = NO;
if ([[PreferenceManager sharedInstance] getBooleanPref:"chimera.enable_rendezvous" withSuccess:&success])
if ([pm getBooleanPref:"chimera.enable_rendezvous" withSuccess:&success])
{
// are we on 10.2.3 or higher? The DNS resolution stuff is broken before 10.2.3
long systemVersion;
OSErr err = ::Gestalt(gestaltSystemVersion, &systemVersion);
if ((err == noErr) && (systemVersion >= 0x00001023))
{
mNetworkServices = [[NetworkServices alloc] init];
[mNetworkServices registerClient:self];
[mNetworkServices startServices];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:@selector(availableServicesChanged:) name:NetworkServicesAvailableServicesChanged object:nil];
[nc addObserver:self selector:@selector(serviceResolved:) name:NetworkServicesResolutionSuccess object:nil];
[nc addObserver:self selector:@selector(serviceResolutionFailed:) name:NetworkServicesResolutionFailure object:nil];
doingRendezvous = YES;
}
}
@ -277,9 +256,10 @@ const int kReuseWindowOnAE = 2;
NSLog(@"App will terminate notification");
#endif
[mNetworkServices unregisterClient:self];
[mNetworkServices release];
[NetworkServices shutdownNetworkServices];
[[BookmarkManager sharedBookmarkManager] shutdown];
// Autosave one of the windows.
[[[mApplication mainWindow] windowController] autosaveWindowFrame];
@ -288,18 +268,10 @@ const int kReuseWindowOnAE = 2;
// make sure the info window is closed
[BookmarkInfoController closeBookmarkInfoController];
BookmarksManager* bmManager = [BookmarksManager sharedBookmarksManagerDontAlloc];
if (bmManager)
{
[bmManager removeBookmarksClient:mMenuBookmarks];
[bmManager removeBookmarksClient:mDockBookmarks];
}
// Release before calling TermEmbedding since we need to access XPCOM
// to save preferences
[mPreferencesController release];
[mPreferenceManager release];
CHBrowserService::TermEmbedding();
@ -339,6 +311,39 @@ const int kReuseWindowOnAE = 2;
}
}
//
// this gets called by bookmark load background thread, so it's a possible
// point of contention. but, it's only called once on startup, so probably
// won't be a problem.
//
- (void)setupBookmarkMenus:(BookmarkManager *)BookmarkManager
{
[mBookmarksMenu setAutoenablesItems: NO];
// menubar bookmarks
int firstBookmarkItem = [mBookmarksMenu indexOfItemWithTag:kBookmarksDividerTag] + 1;
mMenuBookmarks = [[BookmarkMenu alloc] initWithMenu: mBookmarksMenu
firstItem: firstBookmarkItem
rootBookmarkFolder: [BookmarkManager bookmarkMenuFolder]];
// dock bookmarks. Note that we disable them on 10.1 because of a bug noted here:
// http://developer.apple.com/samplecode/Sample_Code/Cocoa/DeskPictAppDockMenu.htm
if (NSAppKitVersionNumber >= kFixedDockMenuAppKitVersion)
{
[mDockMenu setAutoenablesItems:NO];
int firstBookmarkItem = [mDockMenu indexOfItemWithTag:kBookmarksDividerTag] + 1;
mDockBookmarks = [[BookmarkMenu alloc] initWithMenu: mDockMenu
firstItem: firstBookmarkItem
rootBookmarkFolder: [BookmarkManager dockMenuFolder]];
}
else
{
// just empty the menu
while ([mDockMenu numberOfItems] > 0)
[mDockMenu removeItemAtIndex:0];
}
}
-(IBAction)newWindow:(id)aSender
{
@ -349,7 +354,7 @@ const int kReuseWindowOnAE = 2;
[[mainWindow windowController] autosaveWindowFrame];
// Now open the new window.
NSString* homePage = mStartURL ? mStartURL : [mPreferenceManager homePage:YES];
NSString* homePage = mStartURL ? mStartURL : [[PreferenceManager sharedInstance] homePage:YES];
BrowserWindowController* controller = [self openBrowserWindowWithURL:homePage andReferrer:nil];
if ([homePage isEqualToString: @"about:blank"])
@ -612,9 +617,9 @@ const int kReuseWindowOnAE = 2;
- (void)adjustBookmarksMenuItemsEnabling:(BOOL)inBrowserWindowFrontmost;
{
[mAddBookmarkMenuItem setEnabled:inBrowserWindowFrontmost];
[mCreateBookmarksFolderMenuItem setEnabled:inBrowserWindowFrontmost];
[mCreateBookmarksSeparatorMenuItem setEnabled:NO]; // separators are not implemented yet
[mAddBookmarkMenuItem setEnabled:inBrowserWindowFrontmost];
[mCreateBookmarksFolderMenuItem setEnabled:inBrowserWindowFrontmost];
[mCreateBookmarksSeparatorMenuItem setEnabled:YES];
}
- (NSView*)getSavePanelView
@ -671,7 +676,7 @@ const int kReuseWindowOnAE = 2;
- (void)openNewWindowOrTabWithURL:(NSString*)inURLString andReferrer: (NSString*)aReferrer
{
// make sure we're initted
[self preferenceManager];
[PreferenceManager sharedInstance];
PRInt32 reuseWindow = 0;
PRBool loadInBackground = PR_FALSE;
@ -712,31 +717,7 @@ const int kReuseWindowOnAE = 2;
// Bookmarks menu actions.
-(IBAction) importBookmarks:(id)aSender
{
// IE favorites: ~/Library/Preferences/Explorer/Favorites.html
// Omniweb favorites: ~/Library/Application Support/Omniweb/Bookmarks.html
// For now, open the panel to IE's favorites.
NSOpenPanel* openPanel = [NSOpenPanel openPanel];
[openPanel setCanChooseFiles: YES];
[openPanel setCanChooseDirectories: NO];
[openPanel setAllowsMultipleSelection: NO];
NSArray* array = [NSArray arrayWithObjects: @"htm",@"html",@"xml", nil];
int result = [openPanel runModalForDirectory: @"~/Library/Preferences/Explorer/"
file: @"Favorites.html"
types: array];
if (result == NSOKButton) {
NSArray* urlArray = [openPanel URLs];
if ([urlArray count] == 0)
return;
NSURL* url = [urlArray objectAtIndex: 0];
NSWindow* browserWindow = [self getFrontmostBrowserWindow];
if (!browserWindow) {
[self newWindow: self];
browserWindow = [mApplication mainWindow];
}
[[browserWindow windowController] importBookmarks: [url absoluteString]];
}
[[BookmarkManager sharedBookmarkManager] startImportBookmarks];
}
-(IBAction) exportBookmarks:(id)aSender
@ -748,10 +729,7 @@ const int kReuseWindowOnAE = 2;
int saveResult = [savePanel runModalForDirectory:@"" file:@"Exported Bookmarks"];
if (saveResult != NSFileHandlingPanelOKButton)
return;
nsAutoString filePath;
[[savePanel filename] assignTo_nsAString:filePath];
BookmarksService::ExportBookmarksToHTML(filePath);
[[BookmarkManager sharedBookmarkManager] writeHTMLFile:[savePanel filename]];
}
-(IBAction) addBookmark:(id)aSender
@ -778,11 +756,15 @@ const int kReuseWindowOnAE = 2;
if ([aSender isMemberOfClass:[NSApplication class]])
return; // 10.1. Don't do anything.
BookmarksManager* bmManager = [BookmarksManager sharedBookmarksManager];
BookmarkItem* item = [bmManager getWrapperForID:[aSender tag]];
if ([item isGroup])
{
BookmarkItem* item = [aSender representedObject];
BrowserWindowController* browserController;
if ([item isKindOfClass:[Bookmark class]]) {
browserController = [self getMainWindowBrowserController];
if (browserController)
[browserController loadURL:[(Bookmark *)item url] referrer:nil activate:YES];
else
[self openBrowserWindowWithURL:[(Bookmark *)item url] andReferrer:nil];
} else { // item is a group, no doubt.
NSWindow* browserWindow = [self getFrontmostBrowserWindow];
if (browserWindow)
{
@ -794,20 +776,8 @@ const int kReuseWindowOnAE = 2;
[self newWindow:self];
browserWindow = [self getFrontmostBrowserWindow];
}
BrowserWindowController* browserController = (BrowserWindowController*)[browserWindow delegate];
NSArray* uriList = [bmManager getBookmarkGroupURIs:item];
[browserController openTabGroup:uriList replaceExistingTabs:YES];
}
else
{
NSString* url = [item url];
BrowserWindowController* browserController = [self getMainWindowBrowserController];
if (browserController)
[browserController loadURL:url referrer:nil activate:YES];
else
[self openBrowserWindowWithURL:url andReferrer:nil];
browserController = (BrowserWindowController*)[browserWindow delegate];
[browserController openTabGroup:[(BookmarkFolder *)item childURLs] replaceExistingTabs:YES];
}
}
@ -832,13 +802,6 @@ const int kReuseWindowOnAE = 2;
[[browserWindow windowController] manageHistory: aSender];
}
- (PreferenceManager *)preferenceManager
{
if (!mPreferenceManager)
mPreferenceManager = [[PreferenceManager sharedInstance] retain];
return mPreferenceManager;
}
- (MVPreferencesController *)preferencesController
{
if (!mPreferencesController) {
@ -1004,7 +967,7 @@ const int kReuseWindowOnAE = 2;
// out this menu.
if (action == @selector(toggleBookmarksToolbar:)) {
if (browserController) {
NSView* bookmarkToolbar = [browserController bookmarksToolbar];
NSView* bookmarkToolbar = [browserController bookmarkToolbar];
if ( bookmarkToolbar ) {
float height = [bookmarkToolbar frame].size.height;
BOOL toolbarShowing = (height > 0);
@ -1022,21 +985,10 @@ const int kReuseWindowOnAE = 2;
}
if (action == @selector(toggleSidebar:)) {
if (browserController) {
NSDrawer *sidebar = [browserController sidebarDrawer];
if (sidebar) {
int sidebarState = [sidebar state];
if (sidebarState == NSDrawerOpenState)
[mToggleSidebarMenuItem setTitle: NSLocalizedString(@"HideSidebarMenuItem",@"")];
else
[mToggleSidebarMenuItem setTitle: NSLocalizedString(@"ShowSidebarMenuItem",@"")];
return YES;
}
else
return NO;
}
else
return NO;
if (browserController)
return YES;
else
return NO;
}
if ( action == @selector(getInfo:) )
@ -1103,10 +1055,10 @@ const int kReuseWindowOnAE = 2;
BrowserWindowController* browserController = [self getMainWindowBrowserController];
if (!browserController) return;
float height = [[browserController bookmarksToolbar] frame].size.height;
float height = [[browserController bookmarkToolbar] frame].size.height;
BOOL showToolbar = (BOOL)(!(height > 0));
[[browserController bookmarksToolbar] showBookmarksToolbar: showToolbar];
[[browserController bookmarkToolbar] showBookmarksToolbar: showToolbar];
// save prefs here
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
@ -1262,26 +1214,30 @@ static int SortByProtocolAndName(NSDictionary* item1, NSDictionary* item2, void
return [[item1 objectForKey:@"protocol"] compare:[item2 objectForKey:@"protocol"] options:NSCaseInsensitiveSearch];
}
- (void)rebuildNetServiceMenu
// NetworkServicesClient implementation
- (void)availableServicesChanged:(NSNotification *)note
{
// rebuild the submenu, leaving the first item
while ([mServersSubmenu numberOfItems] > 1)
[mServersSubmenu removeItemAtIndex:[mServersSubmenu numberOfItems] - 1];
NSEnumerator* keysEnumerator = [mNetworkServices serviceEnumerator];
NetworkServices *netserv = [note object];
NSEnumerator* keysEnumerator = [netserv serviceEnumerator];
// build an array of dictionaries, so we can sort it
NSMutableArray* servicesArray = [[NSMutableArray alloc] initWithCapacity:10];
id key;
while ((key = [keysEnumerator nextObject]))
{
NSDictionary* serviceDict = [NSDictionary dictionaryWithObjectsAndKeys:
key, @"id",
[mNetworkServices serviceName:[key intValue]], @"name",
[mNetworkServices serviceProtocol:[key intValue]], @"protocol",
nil];
key, @"id",
[netserv serviceName:[key intValue]], @"name",
[netserv serviceProtocol:[key intValue]], @"protocol",
nil];
[servicesArray addObject:serviceDict];
}
@ -1302,7 +1258,8 @@ static int SortByProtocolAndName(NSDictionary* item1, NSDictionary* item2, void
// sort on protocol, then name
[servicesArray sortUsingFunction:SortByProtocolAndName context:NULL];
for (unsigned int i = 0; i < [servicesArray count]; i ++)
unsigned count = [servicesArray count];
for (unsigned int i = 0; i < count; i ++)
{
NSDictionary* serviceDict = [servicesArray objectAtIndex:i];
NSString* itemName = [[serviceDict objectForKey:@"name"] stringByAppendingString:NSLocalizedString([serviceDict objectForKey:@"protocol"], @"")];
@ -1312,40 +1269,40 @@ static int SortByProtocolAndName(NSDictionary* item1, NSDictionary* item2, void
[newItem setTarget:self];
}
}
// when you alloc, you've got to release . . .
[servicesArray release];
}
// NetworkServicesClient implementation
- (void)availableServicesChanged:(NetworkServices*)servicesProvider
- (void)serviceResolved:(NSNotification *)note
{
[self rebuildNetServiceMenu];
NSDictionary *dict = [note userInfo];
if ([dict objectForKey:NetworkServicesClientKey] == self)
[self openNewWindowOrTabWithURL:[dict objectForKey:NetworkServicesResolvedURLKey] andReferrer:nil];
}
- (void)serviceResolved:(int)serviceID withURL:(NSString*)url
//
// handles resolution failure for everybody else
//
- (void)serviceResolutionFailed:(NSNotification *)note
{
[self openNewWindowOrTabWithURL:url andReferrer:nil];
}
- (void)serviceResolutionFailed:(int)serviceID
{
NSString* serviceName = [mNetworkServices serviceName:serviceID];
NSDictionary *dict = [note userInfo];
NSString* serviceName = [dict objectForKey:NetworkServicesServiceKey];
NSBeginAlertSheet(NSLocalizedString(@"ServiceResolutionFailedTitle", @""),
@"", // default button
nil, // cancel buttton
nil, // other button
[NSApp mainWindow], // window
nil, // delegate
nil, // end sel
nil, // dismiss sel
NULL, // context
[NSString stringWithFormat:NSLocalizedString(@"ServiceResolutionFailedMsgFormat", @""), serviceName]
);
@"", // default button
nil, // cancel buttton
nil, // other button
[NSApp mainWindow], // window
nil, // delegate
nil, // end sel
nil, // dismiss sel
NULL, // context
[NSString stringWithFormat:NSLocalizedString(@"ServiceResolutionFailedMsgFormat", @""), serviceName]
);
}
-(IBAction) connectToServer:(id)aSender
{
[mNetworkServices attemptResolveService:[aSender tag]];
[[NetworkServices sharedNetworkServices] attemptResolveService:[aSender tag] forSender:self];
}
-(IBAction) aboutServers:(id)aSender

Просмотреть файл

@ -0,0 +1,62 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Nathan Day (original author)
* David Haas <haasd@cae.wisc.edu>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* This class is taken whole cloth from "NDRunLoopMessenger", written by
* Nathan Day. All I did was remove a couple methods and change some strings.
* The original code can be found at:
* http://homepage.mac.com/nathan_day/pages/source.html#NDRunLoopMessenger
*
* ***** END LICENSE BLOCK ***** */
#import <Foundation/Foundation.h>
@interface RunLoopMessenger : NSObject
{
NSPort* mPort;
}
+ (id)runLoopMessengerForCurrentRunLoop;
- (void)target:(id)aTarget performSelector:(SEL)aSelector;
- (void)target:(id)aTarget performSelector:(SEL)aSelector withObjects:(NSArray *)objectArray;
- (id)target:(id)aTarget performSelector:(SEL)aSelector withResult:(BOOL)aResultFlag;
- (id)target:(id)aTarget performSelector:(SEL)aSelector withObjects:(NSArray *)objectArray withResult:(BOOL)aResultFlag;
- (void)messageInvocation:(NSInvocation *)anInvocation withResult:(BOOL)aResultFlag;
@end

Просмотреть файл

@ -0,0 +1,250 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Nathan Day (original author)
* David Haas <haasd@cae.wisc.edu>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* This class is taken whole cloth from "NDRunLoopMessenger", written by
* Nathan Day. I removed a couple methods, changed some strings, and made
* the tinest tweaks to sendData() & messageInvocation:withResult.
* The original code can be found at:
* http://homepage.mac.com/nathan_day/pages/source.html#NDRunLoopMessenger
*
* A big problem with this code is that the send loop can fill up, which blocks
* the thread this gets run on. I noticed this when checking bookmark imports.
* Storing things in a queue would be clever, but I'm not that clever.
*
* ***** END LICENSE BLOCK ***** */
#import "RunLoopMessenger.h"
static NSString* kThreadDictionaryKey = @"nd_rml_tdk";
static NSString* kSendMessageException = @"nd_rlm_sme";
static NSString* kConnectionDoesNotExistsException = @"nd_rlm_cdnee";
//
//struct message
//
struct message
{
NSConditionLock* resultLock;
NSInvocation* invocation;
};
//
// function sendData
//
void sendData(NSData * aData, NSPort * aPort);
//
// interface RunLoopMessenger
//
@interface RunLoopMessenger (Private)
- (void)createPortForRunLoop:(NSRunLoop *)aRunLoop;
- (void)registerNotificationObservers;
@end
@implementation RunLoopMessenger
+ (id)runLoopMessengerForCurrentRunLoop
{
RunLoopMessenger* currentRunLoopMessenger;
currentRunLoopMessenger = [[[NSThread currentThread] threadDictionary] objectForKey:kThreadDictionaryKey];
if( currentRunLoopMessenger == nil )
currentRunLoopMessenger = [[RunLoopMessenger alloc] init];
return currentRunLoopMessenger;
}
- (id)init
{
if((self = [super init]))
{
NSMutableDictionary* theThreadDictionary;
id theOneForThisThread;
theThreadDictionary = [[NSThread currentThread] threadDictionary];
if((theOneForThisThread = [theThreadDictionary objectForKey:kThreadDictionaryKey]))
{
[self release];
self = theOneForThisThread;
}
else
{
[self createPortForRunLoop:[NSRunLoop currentRunLoop]];
[theThreadDictionary setObject:self forKey:kThreadDictionaryKey];
[self registerNotificationObservers];
}
}
return self;
}
- (void)registerNotificationObservers
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(threadWillExit:) name:NSThreadWillExitNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(portDidBecomeInvalid:) name:NSPortDidBecomeInvalidNotification object:mPort];
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[[NSThread currentThread] threadDictionary] removeObjectForKey:kThreadDictionaryKey];
[mPort removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[mPort release];
[super dealloc];
}
- (void)threadWillExit:(NSNotification *)notification
{
NSThread* thread = [notification object];
if( [[thread threadDictionary] objectForKey:kThreadDictionaryKey] == self )
{
[[thread threadDictionary] removeObjectForKey:kThreadDictionaryKey];
[mPort removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
mPort= nil;
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
}
- (void)portDidBecomeInvalid:(NSNotification *)notification
{
if( [notification object] == mPort)
{
[[[NSThread currentThread] threadDictionary] removeObjectForKey:kThreadDictionaryKey];
[mPort removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
mPort= nil;
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
}
- (void)target:(id)aTarget performSelector:(SEL)aSelector
{
[self target:aTarget performSelector:aSelector withObjects:nil withResult:NO];
}
- (void)target:(id)aTarget performSelector:(SEL)aSelector withObjects:(NSArray *)anArray
{
[self target:aTarget performSelector:aSelector withObjects:anArray withResult:NO];
}
- (id)target:(id)aTarget performSelector:(SEL)aSelector withResult:(BOOL)aFlag
{
return [self target:aTarget performSelector:aSelector withObjects:nil withResult:aFlag];
}
- (id)target:(id)aTarget performSelector:(SEL)aSelector withObjects:(NSArray *)anArray withResult:(BOOL)aFlag
{
NSInvocation* theInvocation;
id anArgument, theResult = nil;
unsigned i,count;
theInvocation = [NSInvocation invocationWithMethodSignature:[aTarget methodSignatureForSelector:aSelector]];
[theInvocation setSelector:aSelector];
[theInvocation setTarget:aTarget];
if (anArray) {
count = [anArray count];
for (i=0;i < count;i++) {
anArgument = [anArray objectAtIndex:i];
[theInvocation setArgument:&anArgument atIndex:(i+2)];
}
}
[self messageInvocation:theInvocation withResult:aFlag];
if( aFlag )
[theInvocation getReturnValue:&theResult];
return theResult;
}
- (void)messageInvocation:(NSInvocation *)anInvocation withResult:(BOOL)aResultFlag
{
struct message* theMessage;
NSMutableData* theData;
[anInvocation retainArguments];
theData = [NSMutableData dataWithLength:sizeof(struct message)];
theMessage = (struct message *)[theData mutableBytes];
theMessage->invocation = [anInvocation retain]; // will be released by handlePortMessage
theMessage->resultLock = aResultFlag ? [[NSConditionLock alloc] initWithCondition:NO] : nil;
NS_DURING
sendData(theData,mPort);
NS_HANDLER
[theMessage->invocation release];
[theMessage->resultLock unlock];
[theMessage->resultLock release];
return;
NS_ENDHANDLER
if(aResultFlag)
{
[theMessage->resultLock lockWhenCondition:YES];
[theMessage->resultLock unlock];
[theMessage->resultLock release];
}
}
- (void)handlePortMessage:(NSPortMessage *)aPortMessage
{
struct message* theMessage;
NSData* theData;
theData = [[aPortMessage components] lastObject];
theMessage = (struct message*)[theData bytes];
[theMessage->invocation invoke];
if( theMessage->resultLock )
{
[theMessage->resultLock lock];
[theMessage->resultLock unlockWithCondition:YES];
}
[theMessage->invocation release]; // to balance messageInvocation:withResult:
}
- (void)createPortForRunLoop:(NSRunLoop *)aRunLoop
{
mPort = [NSPort port];
[mPort setDelegate:self];
[mPort scheduleInRunLoop:aRunLoop forMode:NSDefaultRunLoopMode];
}
void sendData(NSData* aData, NSPort* aPort)
{
NSPortMessage* thePortMessage;
if(aPort)
{
thePortMessage = [[NSPortMessage alloc] initWithSendPort:aPort receivePort:nil components:[NSArray arrayWithObject:aData]];
if(![thePortMessage sendBeforeDate:[NSDate dateWithTimeIntervalSinceNow:15.0]])
[NSException raise:kSendMessageException format:@"An error occured will trying to send the message data %@", [aData description]];
[thePortMessage release];
}
else
{
[NSException raise:kConnectionDoesNotExistsException format:@"The connection to the runLoop does not exist"];
}
}
@end

Просмотреть файл

@ -0,0 +1,59 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* David Haas <haasd@cae.wisc.edu>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* Lets us have address book code and still run on 10.1. When/if 10.1
* support goes away, merge this into SmartBookmarkManger class.
*
* ***** END LICENSE BLOCK ***** */
#import <Foundation/Foundation.h>
@interface AddressBookManager : NSObject
{
//
// leave this an id for 10.1 support. when you go to 10.2
// this whole class should disappear, and the methods should just
// get merged into KindaSmartFolderManager.
id mAddressBookFolder;
}
-(void)fillAddressBook:(NSNotification *)note;
@end

Просмотреть файл

@ -0,0 +1,91 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* David Haas <haasd@cae.wisc.edu>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* Lets us have address book code and still run on 10.1. When/if 10.1
* support goes away, merge this into KindaSmartFolderManger class.
*
* ***** END LICENSE BLOCK ***** */
#import "AddressBookManager.h"
#import <AddressBook/AddressBook.h>
@implementation AddressBookManager
-(id)initWithFolder:(id)folder
{
if ((self = [super init])) {
mAddressBookFolder = [folder retain];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:@selector(fillAddressBook:) name:kABDatabaseChangedNotification object:nil];
[nc addObserver:self selector:@selector(fillAddressBook:) name: kABDatabaseChangedExternallyNotification object:nil];
[self fillAddressBook:nil];
}
return self;
}
-(void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[mAddressBookFolder release];
[super dealloc];
}
-(void)fillAddressBook:(NSNotification *)note
{
// to fill, you must empty.
unsigned i, count = [mAddressBookFolder count];
for (i=0; i < count; i++)
[mAddressBookFolder deleteChild:[mAddressBookFolder objectAtIndex:0]];
// fill address book with people. could probably do this smarter,
// but it's a start for now.
ABAddressBook *ab = [ABAddressBook sharedAddressBook];
NSEnumerator *peopleEnumerator = [[ab people] objectEnumerator];
ABPerson* person;
NSString *name, *homepage;
while ((person = [peopleEnumerator nextObject])) {
homepage = [person valueForProperty:kABHomePageProperty];
if ([homepage length] > 0) {
name = [NSString stringWithFormat:@"%@ %@",[person valueForProperty:kABFirstNameProperty],[person valueForProperty:kABLastNameProperty]];
id bookmark = [mAddressBookFolder addBookmark];
[bookmark setTitle:name];
[bookmark setUrl:homepage];
}
}
}
@end

Просмотреть файл

@ -0,0 +1,79 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* David Haas <haasd@cae.wisc.edu>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import "BookmarkItem.h"
//Status Flags
#define kBookmarkOKStatus 0
#define kBookmarkBrokenLinkStatus 1
#define kBookmarkMovedLinkStatus 2
#define kBookmarkServerErrorStatus 3
#define kBookmarkNeverCheckStatus 5
#define kBookmarkSpacerStatus 9
@interface Bookmark : BookmarkItem //DBME
{
NSString* mURL; //DBMu
NSDate* mLastVisit; //DBMv
NSNumber* mStatus;
NSNumber* mNumberOfVisits;
}
-(NSString *) url;
-(NSDate *) lastVisit;
-(unsigned) numberOfVisits;
-(unsigned) status;
-(BOOL) isMoved;
-(BOOL) isCheckable;
-(BOOL) isSeparator;
-(BOOL) isSick; //DHIs
-(void) setUrl:(NSString *)aURL;
-(void) setLastVisit:(NSDate *)aLastVisit;
-(void) setStatus:(unsigned)aStatus;
-(void) setIsSeparator:(BOOL)aSeparatorFlag;
-(void) setNumberOfVisits:(unsigned)aNumber;
// functions aiding in checking for updates
-(NSURL *)urlAsURL;
-(void) checkForUpdate;
@end

Просмотреть файл

@ -0,0 +1,632 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* David Haas <haasd@cae.wisc.edu>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import <SystemConfiguration/SystemConfiguration.h>
#import "Bookmark.h"
#import "BookmarkFolder.h"
#import "BookmarkManager.h"
#import "BookmarksClient.h"
#import "NSString+Utils.h"
#import "SiteIconProvider.h"
@interface Bookmark (Private)
-(void) siteIconCheck:(NSNotification *)aNote;
-(void) urlLoadCheck:(NSNotification *)aNote;
-(void) invalidSchemeForUpdating;
-(BOOL) hostIsReachable:(NSURL *)aURL;
-(void) doHTTPUpdateRequest:(NSURL *)aURL;
-(void) doFileUpdateRequest:(NSURL *)aURL;
-(void) interpretHTTPUpdateCode:(UInt32) aCode;
-(void) cleanupHTTPCheck:(NSTimer *)aTimer;
-(NSString *)userAgentString;
@end
// Constants - for update status checking
static const CFOptionFlags kNetworkEvents = kCFStreamEventEndEncountered | kCFStreamEventErrorOccurred;
// Notification of URL load
NSString *URLLoadNotification = @"url_load";
NSString *URLLoadSuccessKey = @"url_bool";
@implementation Bookmark
-(id) init
{
if ((self = [super init])) {
mURL = [[NSString alloc] init];
NSNumber *tempNumber = [[NSNumber alloc] initWithUnsignedInt:0];
mStatus = [tempNumber retain];
mNumberOfVisits = [tempNumber retain];
[tempNumber release];
mLastVisit = [[NSDate date] retain];
mIcon = [[NSImage imageNamed:@"smallbookmark"] retain];
// register for notifications
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:@selector(siteIconCheck:) name:SiteIconLoadNotificationName object:nil];
[nc addObserver:self selector:@selector(urlLoadCheck:) name:URLLoadNotification object:nil];
}
return self;
}
-(id) copyWithZone:(NSZone *)zone
{
id doppleganger = [super copyWithZone:zone];
[doppleganger setUrl:[self url]];
[doppleganger setStatus:[self status]];
[doppleganger setLastVisit:[self lastVisit]];
[doppleganger setNumberOfVisits:[self numberOfVisits]];
return doppleganger;
}
- (void) dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
mParent = NULL; // not retained, so just set to null
[mURL release];
[mLastVisit release];
[mStatus release];
[mNumberOfVisits release];
[super dealloc];
}
// set/get properties
-(NSString *) url
{
return mURL;
}
-(NSDate *) lastVisit
{
return mLastVisit;
}
-(unsigned) status
{
return [mStatus unsignedIntValue];
}
-(unsigned) numberOfVisits
{
return [mNumberOfVisits unsignedIntValue];
}
-(BOOL) isSeparator
{
if ([self status]==kBookmarkSpacerStatus)
return YES;
return NO;
}
-(BOOL) isMoved
{
if ([self status]==kBookmarkMovedLinkStatus)
return YES;
return NO;
}
-(BOOL) isCheckable
{
unsigned myStatus = [self status];
if (myStatus!=kBookmarkNeverCheckStatus &&
myStatus!=kBookmarkBrokenLinkStatus &&
myStatus!=kBookmarkSpacerStatus)
return YES;
return NO;
}
-(BOOL) isSick
{
if (([self status]==kBookmarkBrokenLinkStatus) || ([self status]==kBookmarkServerErrorStatus))
return YES;
return NO;
}
-(void) setStatus:(unsigned)aStatus
{
if ((aStatus != [mStatus unsignedIntValue]) &&
((aStatus == kBookmarkBrokenLinkStatus) ||
(aStatus == kBookmarkMovedLinkStatus) ||
(aStatus == kBookmarkOKStatus) ||
(aStatus == kBookmarkSpacerStatus) ||
(aStatus == kBookmarkServerErrorStatus) ||
(aStatus == kBookmarkNeverCheckStatus)))
{
[mStatus release];
mStatus = [[NSNumber alloc] initWithUnsignedInt:aStatus];
[self itemUpdatedNote];
if (aStatus == kBookmarkSpacerStatus)
[self setTitle:NSLocalizedString(@"<Menu Spacer>",@"<Menu Spacer>")];
}
}
- (void) setUrl:(NSString *)aURL
{
if (aURL) {
[aURL retain];
[mURL release];
mURL = aURL;
[self setStatus:kBookmarkOKStatus];
[self refreshIcon];
}
}
- (void) setLastVisit:(NSDate *)aDate
{
if (aDate) {
[aDate retain];
[mLastVisit release];
mLastVisit = aDate;
}
}
-(void) setNumberOfVisits:(unsigned)aNumber
{
[mNumberOfVisits release];
mNumberOfVisits = [[NSNumber alloc] initWithUnsignedInt:aNumber];
[self itemUpdatedNote];
}
-(void) setIsSeparator:(BOOL)aBool
{
if (aBool)
[self setStatus:kBookmarkSpacerStatus];
else
[self setStatus:kBookmarkOKStatus];
}
-(void) refreshIcon
{
if ([BookmarkManager sharedBookmarkManager]) {
[[SiteIconProvider sharedFavoriteIconProvider] loadFavoriteIcon:self forURI:[self url] allowNetwork:NO];
}
}
-(void) siteIconCheck:(NSNotification *)note
{
NSDictionary *userInfo = [note userInfo];
if (userInfo) {
id loadTarget = [note object];
NSString *iconString = [userInfo objectForKey:SiteIconLoadUserDataKey];
if (iconString) {
NSURL *iconURL= [NSURL URLWithString:[NSString escapedURLString:iconString]];
NSURL *myURL = [NSURL URLWithString:[NSString escapedURLString:[self url]]];
if ((loadTarget == self) || [iconURL isEqual:myURL] || [[[iconURL host] stripWWW] isEqualToString:[[myURL host] stripWWW]]) {
NSImage *iconImage = [userInfo objectForKey:SiteIconLoadImageKey];
if (iconImage)
[self setIcon:iconImage];
}
}
}
}
//
// from loads, we only get success or failure - not why things failed.
// so we'll call everything "server error"
//
-(void) urlLoadCheck:(NSNotification *)note
{
NSString *loadedURL = [note object];
if ([loadedURL hasSuffix:@"/"])
loadedURL = [loadedURL substringToIndex:([loadedURL length]-1)];
NSString *myURL = [self url];
if ([myURL hasSuffix:@"/"])
myURL = [myURL substringToIndex:([myURL length]-1)];
if ([loadedURL isEqualToString:myURL]) {
unsigned loadStatus = [[[note userInfo] objectForKey:URLLoadSuccessKey] unsignedIntValue];
[self setLastVisit:[NSDate date]];
[self setStatus:loadStatus];
if (loadStatus == kBookmarkOKStatus)
[self setNumberOfVisits:([self numberOfVisits]+1)];
}
}
#pragma mark -
//
// handles checking for updates & whatnot of itself
//
-(NSURL *)urlAsURL
{
// We'll just assume if there's a # it's a fragment marker. Yes,
// this is almost certainly a bug, but just for checking status so who cares.
NSString *escapedURL = (NSString *)CFURLCreateStringByAddingPercentEscapes
(NULL,(CFStringRef)[self url],CFSTR("#"),NULL,kCFStringEncodingUTF8);
NSURL *myURL = [NSURL URLWithString:escapedURL];
[escapedURL release];
return myURL;
}
// for now, we'll only check updates on file or http scheme.
// don't know if https will work.
- (void) checkForUpdate;
{
NSURL* myURL = [self urlAsURL];
if (myURL) {
if ([[myURL scheme] isEqualToString:@"http"] && [self hostIsReachable:myURL])
[self doHTTPUpdateRequest:myURL];
else if ([[myURL scheme] isEqualToString:@"file"])
[self doFileUpdateRequest:myURL];
else
[self setStatus:kBookmarkNeverCheckStatus];
}
}
- (BOOL) hostIsReachable:(NSURL *)aURL
{
const char *hostname = [[aURL host] cString];
if (!hostname)
return NO;
SCNetworkConnectionFlags flags;
// just like TN 1145 instructs, not that we're using CodeWarrior
assert(sizeof(SCNetworkConnectionFlags) == sizeof(int));
BOOL isReachable = NO;
if ( SCNetworkCheckReachabilityByName(hostname, &flags) ) {
isReachable = !(flags & kSCNetworkFlagsConnectionRequired) && (flags & kSCNetworkFlagsReachable);
}
return isReachable;
}
//
// CF Callback functions for handling bookmark updating
//
static void doHTTPUpdateCallBack(CFReadStreamRef stream, CFStreamEventType type, void *bookmark)
{
CFHTTPMessageRef aResponse = NULL;
CFStreamError anError;
NSString *newURL = NULL;
UInt32 errCode;
switch (type){
case kCFStreamEventEndEncountered:
aResponse = (CFHTTPMessageRef) CFReadStreamCopyProperty(stream,kCFStreamPropertyHTTPResponseHeader);
if (aResponse) {
errCode = CFHTTPMessageGetResponseStatusCode(aResponse);
switch (errCode) {
case 301: //permanent move - update URL
newURL = (NSString*)CFHTTPMessageCopyHeaderFieldValue(aResponse,CFSTR("Location"));
[(Bookmark *)bookmark setUrl:newURL];
[newURL release];
break;
default:
[(Bookmark *)bookmark interpretHTTPUpdateCode:errCode];
break;
}
} else //beats me. blame the server.
[(Bookmark *)bookmark interpretHTTPUpdateCode:500];
break;
case kCFStreamEventErrorOccurred:
anError = CFReadStreamGetError(stream);
if (anError.domain == kCFStreamErrorDomainHTTP) {
errCode = anError.error; //signed being assigned to unsinged. oh well
[(Bookmark *)bookmark interpretHTTPUpdateCode:errCode];
} else // call it server error
[(Bookmark *)bookmark interpretHTTPUpdateCode:500];
break;
default:
NSLog(@"If you can read this you're too close to the screen.");
break;
}
//
// update our last visit date & cleanup
//
[(Bookmark *)bookmark setLastVisit:[NSDate date]];
if (aResponse)
CFRelease(aResponse);
}
// borrowed heavily from Apple's CFNetworkHTTPDownload example
-(void) doHTTPUpdateRequest:(NSURL *)aURL
{
CFHTTPMessageRef messageRef = NULL;
CFReadStreamRef readStreamRef = NULL;
CFStreamClientContext ctxt= { 0, (void*)self, NULL, NULL, NULL }; //pointer to self lets us update
// get message
messageRef = CFHTTPMessageCreateRequest(kCFAllocatorDefault, CFSTR("HEAD"), (CFURLRef)aURL, kCFHTTPVersion1_1);
if (!messageRef) {
NSLog(@"CheckForUpdate: Can't create CFHTTPMessage for %@",aURL);
return;
}
// set if-modified-since header field, and maybe others if we're bored.
// really, since we just want to see if it's there, don't even need to
// do this.
NSString *httpDate = [[self lastVisit] descriptionWithCalendarFormat:@"%a, %d %b %Y %H:%M:%S GMT" timeZone:[NSTimeZone timeZoneWithAbbreviation:@"GMT"] locale:nil];
NSString *userAgent = [self userAgentString];
CFHTTPMessageSetHeaderFieldValue(messageRef,CFSTR("If-Modified-Since"),(CFStringRef)httpDate);
CFHTTPMessageSetHeaderFieldValue(messageRef,CFSTR("User-Agent"),(CFStringRef)userAgent);
//setup read stream
readStreamRef = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, messageRef);
CFRelease(messageRef);
if (!readStreamRef) {
NSLog(@"CheckForUpdate: Can't create CFReadStream for %@",aURL);
return;
}
// handle http proxy, if necessary
NSDictionary* proxyConfigDict = (NSDictionary *)SCDynamicStoreCopyProxies(NULL);
if (proxyConfigDict) {
if ([[proxyConfigDict objectForKey:(NSString*)kSCPropNetProxiesHTTPEnable] intValue] != 0) {
NSString *proxyURL = [proxyConfigDict objectForKey:(NSString*)kSCPropNetProxiesHTTPProxy];
NSNumber *proxyPort = [proxyConfigDict objectForKey:(NSString*)kSCPropNetProxiesHTTPPort];
if (proxyURL && proxyPort) {
CFHTTPReadStreamSetProxy(readStreamRef,(CFStringRef)proxyURL,(CFIndex)[proxyPort unsignedIntValue]);
}
}
[proxyConfigDict release];
}
//setup callback function
if (CFReadStreamSetClient(readStreamRef, kNetworkEvents, doHTTPUpdateCallBack, &ctxt ) == false ) {
NSLog(@"CheckForUpdate: Can't set CFReadStream callback for %@",aURL);
CFRelease(readStreamRef);
return;
}
//schedule the stream & open the connection
CFReadStreamScheduleWithRunLoop(readStreamRef, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
if (CFReadStreamOpen(readStreamRef) == false ){
NSLog(@"CheckForUpdate: Can't open CFReadStream for %@",aURL);
CFReadStreamSetClient(readStreamRef, NULL, NULL, NULL);
CFRelease(readStreamRef);
return;
}
//schedule a timeout. we'll give it, oh, 60 seconds before killing the check
//this timer is responsible for cleaning up the read stream memory!!!!!!!!!
[NSTimer scheduledTimerWithTimeInterval:60 target:self selector:@selector(cleanupHTTPCheck:) userInfo:(id)readStreamRef repeats:NO];
}
// My interpretation of what should & shouldn't happen is
// quite possibly incorrect. Feel free to adjust.
-(void) interpretHTTPUpdateCode:(UInt32) errCode
{
switch (errCode){
case 200: //OK - bookmark updated
case 203: //Non-authoritative info - call it same as OK
case 302: //Found - new link, but don't update
case 303: //See other - new link, but don't update
case 304: //Not modified - do nothing
case 307: //Temporary redirect - new link, but don't update
[self setStatus:kBookmarkOKStatus];
break;
case 300: //multiple choices - not sure what to do so we'll bail here
case 301: //Moved permananently - should be handled in callback
case 305: //Use proxy (specified) - should retry request
[self setStatus:kBookmarkMovedLinkStatus];
break;
case 400: //Bad request - we f'd up
case 403: //Forbidden - not good
case 404: //Not found - clearly not good
case 410: //Gone - nah nah nahnah, nah nah nahnah, hey hey hey, etc.
[self setStatus:kBookmarkBrokenLinkStatus];
break;
case 401: //Unauthorized - need to be clever about checking this
case 402: //Payment required - funk that.
case 405: //Method not allowed - funk that, too.
case 406: //Not Acceptable - shouldn't happen, but oh well.
case 407: //Proxy Authentication Required - need to be cleverer here
case 411: //Length required - need to be cleverer
case 413: //Request entity too large - shouldn't happen
case 414: //Request URI too large - shouldn't happen
case 415: //Request URI too large - shouldn't happen
case 500: //Internal server error
case 501: //Not Implemented
case 502: //Bad Gateway
case 503: //Service Unavailable
case 504: //Gateway Timeout
case 505: //HTTP Version not supported
[self setStatus:kBookmarkServerErrorStatus];
break;
case 100: //Continue - just ignore
case 101: //Switching protocols - not that smart yet
case 201: //Created - shouldn't happen
case 202: //Accepted - shouldn't happen
case 204: //No content - shouldn't happen
case 205: //Reset content - shouldn't happen
case 206: //Partial content - shouldn't happen for HEAD request
case 408: //Request timeout - shouldn't happen
case 409: //Conflict - shouldn't happen
case 412: //Precondintion failed - shouldn't happen
case 416: //requested range not satisfiable - shouldn't happen
case 417: //Expectation failed - shouldn't happen
default:
break;
}
}
-(void) doFileUpdateRequest:(NSURL *)aURL
{
// if it's here, it's got a scheme of file, so we can call path directly
NSFileManager *fM = [NSFileManager defaultManager];
if (![fM fileExistsAtPath:[aURL path]])
[self setStatus:kBookmarkBrokenLinkStatus];
}
// this function cleans up after our stream request.
// if you get rid of it, we leak memory
-(void) cleanupHTTPCheck:(NSTimer *)aTimer;
{
CFReadStreamRef stream = (CFReadStreamRef)[aTimer userInfo];
CFReadStreamSetClient(stream,NULL,NULL,NULL);
CFRelease(stream);
}
// this is done poorly. if someone feels like doing this more correctly, more power to you.
-(NSString *)userAgentString
{
return [NSString stringWithString:@"Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O) Gecko Camino"];
}
#pragma mark -
//
// for reading/writing from/to disk
//
NSString *BMTitleKey = @"Title";
NSString *BMDescKey = @"Description";
NSString *BMStatusKey = @"Status";
NSString *BMURLKey = @"URL";
NSString *BMKeywordKey = @"Keyword";
NSString *BMLastVisitKey = @"LastVisitedDate";
NSString *BMNumberVisitsKey = @"VisitCount";
NSString *SafariURIDictKey = @"URIDictionary";
NSString *SafariBookmarkTitleKey = @"title";
NSString *SafariURLStringKey = @"URLString";
-(BOOL) readNativeDictionary:(NSDictionary *)aDict
{
[self setTitle:[aDict objectForKey:BMTitleKey]];
[self setDescription:[aDict objectForKey:BMDescKey]];
[self setKeyword:[aDict objectForKey:BMKeywordKey]];
[self setUrl:[aDict objectForKey:BMURLKey]];
[self setLastVisit:[aDict objectForKey:BMLastVisitKey]];
[self setNumberOfVisits:[[aDict objectForKey:BMNumberVisitsKey] unsignedIntValue]];
[self setStatus:[[aDict objectForKey:BMStatusKey] unsignedIntValue]];
return YES;
}
-(BOOL) readSafariDictionary:(NSDictionary *)aDict
{
NSDictionary *uriDict = [aDict objectForKey:SafariURIDictKey];
[self setTitle:[uriDict objectForKey:SafariBookmarkTitleKey]];
[self setUrl:[aDict objectForKey:SafariURLStringKey]];
return YES;
}
-(BOOL) readCaminoXML:(CFXMLTreeRef)aTreeRef
{
CFXMLNodeRef myNode;
CFXMLElementInfo* elementInfoPtr;
myNode = CFXMLTreeGetNode(aTreeRef);
if (myNode) {
// Process our info
if (CFXMLNodeGetTypeCode(myNode)==kCFXMLNodeTypeElement){
elementInfoPtr = (CFXMLElementInfo *)CFXMLNodeGetInfoPtr(myNode);
if (elementInfoPtr) {
NSDictionary* attribDict = (NSDictionary*)elementInfoPtr->attributes;
[self setTitle:[[attribDict objectForKey:@"name"] stringByRemovingAmpEscapes]];
[self setKeyword:[[attribDict objectForKey:@"id"] stringByRemovingAmpEscapes]];
[self setDescription:[[attribDict objectForKey:@"description"] stringByRemovingAmpEscapes]];
[self setUrl:[[attribDict objectForKey:@"href"] stringByRemovingAmpEscapes]];
} else {
NSLog(@"Bookmark:readCaminoXML - elementInfoPtr null, load failed");
return NO;
}
} else {
NSLog(@"Bookmark:readCaminoXML - node not kCFXMLNodeTypeElement, load failed");
return NO;
}
} else {
NSLog(@"Bookmark:readCaminoXML - urk! CFXMLTreeGetNode null, load failed");
return NO;
}
return YES;
}
// for plist in native format
-(NSDictionary *)writeNativeDictionary
{
NSDictionary* dict;
if (![self isSeparator]) {
dict = [NSDictionary dictionaryWithObjectsAndKeys:
mTitle,BMTitleKey,
mKeyword,BMKeywordKey,
mURL,BMURLKey,
mDescription,BMDescKey ,
mLastVisit,BMLastVisitKey,
mNumberOfVisits,BMNumberVisitsKey,
mStatus,BMStatusKey,
nil];
} else {
dict = [NSDictionary dictionaryWithObjectsAndKeys:
mStatus,BMStatusKey,
nil];
}
return dict;
}
-(NSString *)writeHTML:(unsigned int)aPad
{
NSString*formatString;
NSMutableString *padString = [NSMutableString string];
for (unsigned i = 0;i<aPad;i++)
[padString insertString:@" " atIndex:0];
padString = [@" " stringByPaddingToLength:aPad withString:@" " startingAtIndex:0];
if ([mDescription length] > 0)
formatString = [NSString stringWithString:@"%@<DT><A HREF=\"%s\">%s</A>\n%@<DD>%s\n"];
else
formatString = [NSString stringWithString:@"%@<DT><A HREF=\"%s\">%s</A>\n%@\n"];
return [NSString stringWithFormat:formatString,
padString,
[[self url] UTF8String],
[[mTitle stringByAddingAmpEscapes] UTF8String],
padString,
[[mDescription stringByAddingAmpEscapes] UTF8String]];
}
//
// Scripting methods
//
- (NSScriptObjectSpecifier *)objectSpecifier
{
id parent = [self parent];
NSScriptObjectSpecifier *containerRef = [parent objectSpecifier];
unsigned index = [[parent childArray] indexOfObjectIdenticalTo:self];
if (index != NSNotFound) {
// Man, this took forever to figure out.
// DHBookmarks always contained in BookmarkFolder - so make
// sure we set that as the container class description.
NSScriptClassDescription *aRef = (NSScriptClassDescription*)[NSClassDescription classDescriptionForClass:[BookmarkFolder class]];
return [[[NSIndexSpecifier allocWithZone:[self zone]] initWithContainerClassDescription:aRef containerSpecifier:containerRef key:@"childArray" index:index] autorelease];
} else
return nil;
}
@end

Просмотреть файл

@ -0,0 +1,62 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* David Hyatt <hyatt@apple.com> (Original Author)
* David Haas <haasd@cae.wisc.edu>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import <Appkit/Appkit.h>
@class BookmarkItem;
@interface BookmarkButton : NSButton
{
BookmarkItem* mItem;
}
-(id)initWithFrame:(NSRect)frame item:(BookmarkItem*)item;
- (void)setBookmarkItem:(BookmarkItem*)anItem;
- (BookmarkItem*)BookmarkItem;
-(IBAction)openBookmark:(id)aSender;
-(IBAction)openBookmarkInNewTab:(id)aSender;
-(IBAction)openBookmarkInNewWindow:(id)aSender;
-(IBAction)showBookmarkInfo:(id)aSender;
-(IBAction)deleteBookmarks: (id)aSender;
-(IBAction)addFolder:(id)aSender;
@end

Просмотреть файл

@ -0,0 +1,331 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* David Hyatt <hyatt@apple.com> (Original Author)
* David Haas <haasd@cae.wisc.edu>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import "BookmarkButton.h"
#import "NSString+Utils.h"
#import "NSArray+Utils.h"
#import "NSPasteboard+Utils.h"
#import "DraggableImageAndTextCell.h"
#import "BookmarkManager.h"
#import "Bookmark.h"
#import "BookmarkFolder.h"
#import "BookmarkMenu.h"
#import "BookmarkInfoController.h"
#import "BrowserWindowController.h"
#import "MainController.h"
#import "PreferenceManager.h"
@interface BookmarkButton(Private)
- (void)showFolderPopupAction:(id)aSender;
- (void)showFolderPopup:(NSEvent*)event;
@end
@implementation BookmarkButton
- (id)initWithFrame:(NSRect)frame
{
if ( (self = [super initWithFrame:frame]) )
{
DraggableImageAndTextCell* newCell = [[[DraggableImageAndTextCell alloc] init] autorelease];
[newCell setDraggable:YES];
[self setCell:newCell];
[self setBezelStyle: NSRegularSquareBezelStyle];
[self setButtonType: NSMomentaryChangeButton];
[self setBordered: NO];
[self setImagePosition: NSImageLeft];
[self setRefusesFirstResponder: YES];
[self setFont: [NSFont labelFontOfSize: 11.0]];
}
return self;
}
-(id)initWithFrame:(NSRect)frame item:(BookmarkItem*)item
{
if ( (self = [self initWithFrame:frame]) )
{
[self setBookmarkItem:item];
}
return self;
}
- (void)dealloc
{
[mItem release];
[super dealloc];
}
- (void)setBookmarkItem:(BookmarkItem*)aItem
{
[aItem retain];
[mItem release];
mItem = aItem;
[self setTitle:[aItem title]];
[self setImage:[aItem icon]];
[self setTarget:self];
if ([aItem isKindOfClass:[Bookmark class]]) {
[self setAction:@selector(openBookmark:)];
[self setToolTip:[(Bookmark *)aItem url]];
} else {
[[self cell] setClickHoldTimeout:0.5];
if ([(BookmarkFolder *)aItem isGroup])
[self setAction: @selector(openBookmark:)];
else
[self setAction:@selector(showFolderPopupAction:)];
}
}
- (BookmarkItem*)BookmarkItem
{
return mItem;
}
-(IBAction)openBookmark:(id)aSender
{
BrowserWindowController* brController = [[self window] windowController];
// See if we're a group.
BookmarkItem *item = [self BookmarkItem];
if ([item isKindOfClass:[BookmarkFolder class]]) {
if ([(BookmarkFolder *)item isGroup]) {
[brController openTabGroup:[(BookmarkFolder *)item childURLs] replaceExistingTabs:YES];
return;
}
}
// if the command key is down, follow the command-click pref
if (([[NSApp currentEvent] modifierFlags] & NSCommandKeyMask) &&
[[PreferenceManager sharedInstance] getBooleanPref:"browser.tabs.opentabfor.middleclick" withSuccess:NULL])
{
[self openBookmarkInNewTab:aSender];
return;
}
[brController loadURL:[(Bookmark *)item url] referrer:nil activate:YES];
}
-(IBAction)openBookmarkInNewTab:(id)aSender
{
BookmarkItem *item = [self BookmarkItem];
BrowserWindowController* brController = [[self window] windowController];
if ([item isKindOfClass:[Bookmark class]]) {
NSString* hrefStr = [(Bookmark *)item url];
BOOL loadInBackground = [[PreferenceManager sharedInstance] getBooleanPref:"browser.tabs.loadInBackground" withSuccess:NULL];
[brController openNewTabWithURL: hrefStr referrer:nil loadInBackground: loadInBackground];
} else if ([item isKindOfClass:[BookmarkFolder class]]) {
[brController openTabGroup:[(BookmarkFolder *)item childURLs] replaceExistingTabs:YES];
}
}
-(IBAction)openBookmarkInNewWindow:(id)aSender
{
BOOL loadInBackground = [[PreferenceManager sharedInstance] getBooleanPref:"browser.tabs.loadInBackground" withSuccess:NULL];
BrowserWindowController* brController = [[self window] windowController];
// See if we're a bookmark.
BookmarkItem *item = [self BookmarkItem];
if ([item isKindOfClass:[Bookmark class]])
[brController openNewWindowWithURL:[(Bookmark *)item url] referrer: nil loadInBackground: loadInBackground];
// if we get to this else, we better be a group. check just in case i'm wrong.
else if ([item isKindOfClass:[BookmarkFolder class]]) {
if ([(BookmarkFolder *)item isGroup]) {
[brController openNewWindowWithGroupURLs:[(BookmarkFolder *)item childURLs] loadInBackground: loadInBackground];
}
}
return;
}
-(IBAction)showBookmarkInfo:(id)aSender
{
BookmarkInfoController *bic = [BookmarkInfoController sharedBookmarkInfoController];
[bic setBookmark:[self BookmarkItem]];
[bic showWindow:self];
}
-(IBAction)deleteBookmarks: (id)aSender
{
BookmarkItem *item = [self BookmarkItem];
[[item parent] deleteChild:item];
[self removeFromSuperview];
}
-(IBAction)addFolder:(id)aSender
{
BookmarkManager* bmManager = [BookmarkManager sharedBookmarkManager];
BookmarkFolder* toolbarFolder = [bmManager toolbarFolder];
BookmarkFolder* aFolder = [toolbarFolder addBookmarkFolder];
[aFolder setTitle:NSLocalizedString(@"NewBookmarkFolder",@"New Folder")];
}
-(void)drawRect:(NSRect)aRect
{
[super drawRect: aRect];
}
-(NSMenu*)menuForEvent:(NSEvent*)aEvent
{
BookmarkItem *item = [self BookmarkItem];
if (item) {
NSMenu* contextMenu = [[[self superview] menu] copy];
[[contextMenu itemArray] makeObjectsPerformSelector:@selector(setTarget:) withObject: self];
NSString *nulString = [NSString string];
// clean the menu out
int numItems = [contextMenu numberOfItems];
int itemIndex = [contextMenu indexOfItemWithTarget:self andAction:@selector(showBookmarkInfo:)];
while (numItems > (itemIndex+1))
[contextMenu removeItemAtIndex:(--numItems)];
// set up menu
if ([item isKindOfClass:[Bookmark class]]) {
itemIndex = [contextMenu indexOfItemWithTarget:self andAction:@selector(openBookmarkInNewWindow:)];
[[contextMenu itemAtIndex:itemIndex] setTitle:NSLocalizedString(@"Open in New Window",@"Open in New Window")];
itemIndex = [contextMenu indexOfItemWithTarget:self andAction:@selector(openBookmarkInNewTab:)];
[[contextMenu itemAtIndex:itemIndex] setTitle:NSLocalizedString(@"Open in New Tab",@"Open in New Tab")];
} else if ([item isKindOfClass:[BookmarkFolder class]]) {
itemIndex = [contextMenu indexOfItemWithTarget:self andAction:@selector(openBookmarkInNewWindow:)];
[[contextMenu itemAtIndex:itemIndex] setTitle:NSLocalizedString(@"Open Tabs in New Window",@"Open Tabs in New Window")];
itemIndex = [contextMenu indexOfItemWithTarget:self andAction:@selector(openBookmarkInNewTab:)];
[[contextMenu itemAtIndex:itemIndex] setTitle:NSLocalizedString(@"Open in Tabs",@"Open in Tabs")];
}
// if it's a button, it's got to be on toolbar folder, so we can delete & make new folders
NSMenuItem *menuItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Delete",@"Delete") action:@selector(deleteBookmarks:) keyEquivalent:nulString];
[menuItem setTarget:self];
[contextMenu addItem:menuItem];
[menuItem release];
[contextMenu addItem:[NSMenuItem separatorItem]];
// create new folder
menuItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Create New Folder...",@"Create New Folder...") action:@selector(addFolder:) keyEquivalent:nulString];
[menuItem setTarget:self];
[contextMenu addItem:menuItem];
[menuItem release];
return [contextMenu autorelease];
}
return nil;
}
//
// context menu has only what we need
//
-(BOOL)validateMenuItem:(NSMenuItem*)aMenuItem
{
return YES;
}
- (void)showFolderPopupAction:(id)aSender
{
[self showFolderPopup:[NSApp currentEvent]];
}
- (void)showFolderPopup:(NSEvent*)event
{
NSMenu* popupMenu = [[NSMenu alloc] init];
// dummy first item
[popupMenu addItemWithTitle:@"" action:NULL keyEquivalent:@""];
// make a temporary BookmarkMenu to build the menu
BookmarkMenu* bmMenu = [[BookmarkMenu alloc] initWithMenu:popupMenu firstItem:1 rootBookmarkFolder:(BookmarkFolder *)[self BookmarkItem]];
// use a temporary NSPopUpButtonCell to display the menu.
NSPopUpButtonCell *popupCell = [[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:YES];
[popupCell setMenu: popupMenu];
[popupCell setFont:[NSFont labelFontOfSize: 11.0]];
[popupCell trackMouse:event inRect:[self bounds] ofView:self untilMouseUp:YES];
[popupCell release];
[bmMenu release];
[popupMenu release];
}
-(void)mouseDown:(NSEvent*)aEvent
{
[super mouseDown:aEvent];
if ([[self cell] lastClickHoldTimedOut])
[self showFolderPopup:aEvent];
}
- (unsigned int)draggingSourceOperationMaskForLocal:(BOOL)localFlag
{
if (localFlag)
return (NSDragOperationCopy | NSDragOperationGeneric | NSDragOperationMove);
return (NSDragOperationDelete | NSDragOperationGeneric);
}
- (void) mouseDragged: (NSEvent*) aEvent
{
BookmarkItem *item = [self BookmarkItem];
BOOL isSingleBookmark = [item isKindOfClass:[Bookmark class]];
NSPasteboard *pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
NSString *title = [item title];
if (isSingleBookmark)
{
[pboard declareURLPasteboardWithAdditionalTypes:[NSArray arrayWithObject:@"MozBookmarkType"] owner:self];
NSString *url = [(Bookmark *)item url];
NSString *cleanedTitle = [title stringByReplacingCharactersInSet:[NSCharacterSet controlCharacterSet] withString:@" "];
[pboard setDataForURL:url title:cleanedTitle];
}
else
{
[pboard declareTypes:[NSArray arrayWithObject:@"MozBookmarkType"] owner:self];
}
// MozBookmarkType
NSArray *pointerArray = [NSArray dataArrayFromPointerArrayForMozBookmarkDrop:[NSArray arrayWithObject:item]];
[pboard setPropertyList:pointerArray forType: @"MozBookmarkType"];
[self dragImage: [MainController createImageForDragging:[self image] title:title]
at: NSMakePoint(0,NSHeight([self bounds])) offset: NSMakeSize(0,0)
event: aEvent pasteboard: pboard source: self slideBack: YES];
}
- (void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation
{
if (operation == NSDragOperationDelete)
{
NSPasteboard* pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
NSArray* bookmarks = [NSArray pointerArrayFromDataArrayForMozBookmarkDrop:[pboard propertyListForType: @"MozBookmarkType"]];
if (bookmarks)
{
for (unsigned int i = 0; i < [bookmarks count]; ++i)
{
BookmarkItem* item = [bookmarks objectAtIndex:i];
[[item parent] deleteChild:item];
}
}
}
}
@end

Просмотреть файл

@ -0,0 +1,124 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* David Haas <haasd@cae.wisc.edu>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import "BookmarkItem.h"
#import "BookmarksClient.h"
//Special flags
enum {
kBookmarkFolder = 0,
kBookmarkFolderGroup = 1 << 0,
kBookmarkRootFolder = 1 << 1,
kBookmarkToolbarFolder = 1 << 2,
kBookmarkSmartFolder = 1 << 3,
kBookmarkDockMenuFolder = 1 << 4
};
//root AE code: DB14
@class Bookmark;
@interface BookmarkFolder : BookmarkItem //AE code: DBAE
{
NSMutableArray* mChildArray;
NSNumber* mSpecialFlag;
}
-(NSMutableArray *) childArray;
-(NSArray *) childURLs;
-(NSArray *) allChildBookmarks;
-(BOOL) isSpecial;
-(BOOL) isToolbar;
-(BOOL) isRoot;
-(BOOL) isGroup;
-(BOOL) isSmartFolder;
-(BOOL) isDockMenu;
-(void) setChildArray:(NSMutableArray *)aChildArray; //should be private?
-(void) setIsGroup:(BOOL)aGroupFlag; //AE code: DBAg
-(void) setIsRoot:(BOOL)aFlag;
-(void) setIsToolbar:(BOOL)aFlag;
-(void) setIsSmartFolder:(BOOL)aFlag;
-(void) setIsDockMenu:(BOOL)aFlag;
-(void) makeDockMenu:(id)sender;
// Things added to make it work sort of like an array
-(unsigned) count;
-(id) objectAtIndex:(unsigned)index;
-(unsigned)indexOfObject:(id)object;
-(unsigned)indexOfObjectIdenticalTo:(id)object;
// ways to add a new bookmark
-(Bookmark *) addBookmark; //adds to end
-(Bookmark *) addBookmark:(NSString *)aTitle url:(NSString *)aURL inPosition:(unsigned)aIndex isSeparator:(BOOL)aBool;
-(Bookmark *) addBookmark:(NSString *)aTitle inPosition:(unsigned)aIndex keyword:(NSString *)aKeyword url:(NSString *)aURL description:(NSString *)aDescription lastVisit:(NSDate *)aDate status:(unsigned)aStatus isSeparator:(BOOL)aBool;
// ways to add a new bookmark array
-(BookmarkFolder *) addBookmarkFolder; //adds to end
-(BookmarkFolder *) addBookmarkFolder:(NSString *)aTitle inPosition:(unsigned)aIndex isGroup:(BOOL)aFlag;
// Moving & Copying & inserting bookmarks/bookmark arrays
-(void) insertChild:(BookmarkItem *)aChild;
-(void) insertChild:(BookmarkItem *)aChild atIndex:(unsigned)aIndex isMove:(BOOL)aBool;
-(void) moveChild:(BookmarkItem *)aChild toBookmarkFolder:(BookmarkFolder *)aNewParent atIndex:(unsigned)aIndex;
-(void) copyChild:(BookmarkItem *)aChild toBookmarkFolder:(BookmarkFolder *)aNewParent atIndex:(unsigned)aIndex;
// Used for deleting bookmarks/bookmark arrays
-(BOOL) deleteChild:(BookmarkItem *)aChild;
// Smart Folder only methods
-(void) insertIntoSmartFolderChild:(BookmarkItem *)aItem;
-(void) deleteFromSmartFolderChildAtIndex:(unsigned)index;
// generation menus
-(void) buildFlatFolderList:(NSMenu *)menu depth:(unsigned)pad;
// searching
-(NSArray *) resolveKeyword:(NSString *)aString;
-(NSSet *) bookmarksWithString:(NSString *)searchString;
//Scripting - should be a protocol we could use for these
//two, but i'm not sure which one, so we'll declare them here
//and avoid the compiler warning
-(NSArray *) indicesOfObjectsByEvaluatingRelativeSpecifier:(NSRelativeSpecifier *)relSpec;
-(NSArray *) indicesOfObjectsByEvaluatingRangeSpecifier:(NSRangeSpecifier *)rangeSpec;
@end

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,56 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* David Haas <haasd@cae.wisc.edu>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import <AppKit/AppKit.h>
@interface BookmarkImportDlgController : NSWindowController {
IBOutlet NSPopUpButton* mBrowserListButton;
IBOutlet NSButton* mCancelButton;
IBOutlet NSButton* mImportButton;
}
-(void) buildAvailableFileList;
-(IBAction) cancel:(id)aSender;
-(IBAction) import:(id)aSender;
-(IBAction) loadOpenPanel:(id)aSender;
-(IBAction) nullAction:(id)aSender;
@end

Просмотреть файл

@ -0,0 +1,193 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* David Haas <haasd@cae.wisc.edu>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import "BookmarkImportDlgController.h"
#import "BookmarkManager.h"
#import "BookmarkFolder.h"
@implementation BookmarkImportDlgController
-(void) windowDidLoad
{
[self buildAvailableFileList];
}
-(void) buildAvailableFileList
{
// check for common webbrower bookmark files and, if they exist, add to button.
NSFileManager *fm = [NSFileManager defaultManager];
NSMenuItem *browserItem;
NSEnumerator *enumerator;
id aTempItem;
// iCab
NSString *pathString = [[NSString stringWithString:@"~/Library/Preferences/iCab Preferences/Hotlist.html"] stringByExpandingTildeInPath];
if ([fm fileExistsAtPath:pathString]) {
[mBrowserListButton insertItemWithTitle:@"iCab" atIndex:0];
browserItem = [mBrowserListButton itemAtIndex:0];
[browserItem setTarget:self];
[browserItem setAction:@selector(nullAction:)];
[browserItem setRepresentedObject:pathString];
}
// Firebird
pathString = [[NSString stringWithString:@"~/Library/Phoenix/Profiles/default/"] stringByExpandingTildeInPath];
if ([fm fileExistsAtPath:pathString]) {
NSArray *saltArray = [fm directoryContentsAtPath:pathString];
enumerator = [saltArray objectEnumerator];
while ((aTempItem = [enumerator nextObject])) {
if (![aTempItem hasPrefix:@"."])
break;
}
if (aTempItem) {
pathString = [pathString stringByAppendingFormat:@"/%@/bookmarks.html",aTempItem];
if ([fm fileExistsAtPath:pathString]) {
[mBrowserListButton insertItemWithTitle:@"Mozilla Firebird" atIndex:0];
browserItem = [mBrowserListButton itemAtIndex:0];
[browserItem setTarget:self];
[browserItem setAction:@selector(nullAction:)];
[browserItem setRepresentedObject:pathString];
}
}
}
// Netscape/Mozilla
pathString = [[NSString stringWithString:@"~/Library/Mozilla/Profiles/default/"] stringByExpandingTildeInPath];
if ([fm fileExistsAtPath:pathString]) {
NSArray *saltArray = [fm directoryContentsAtPath:pathString];
enumerator = [saltArray objectEnumerator];
while ((aTempItem = [enumerator nextObject])) {
if (![aTempItem hasPrefix:@"."])
break;
}
if (aTempItem) {
pathString = [pathString stringByAppendingFormat:@"/%@/bookmarks.html",aTempItem];
if ([fm fileExistsAtPath:pathString]) {
[mBrowserListButton insertItemWithTitle:@"Netscape/Mozilla" atIndex:0];
browserItem = [mBrowserListButton itemAtIndex:0];
[browserItem setTarget:self];
[browserItem setAction:@selector(nullAction:)];
[browserItem setRepresentedObject:pathString];
}
}
}
// Omniweb
pathString = [[NSString stringWithString:@"~/Library/Application Support/Omniweb/Bookmarks.html"] stringByStandardizingPath];
if ([fm fileExistsAtPath:pathString]) {
[mBrowserListButton insertItemWithTitle:@"Omniweb" atIndex:0];
browserItem = [mBrowserListButton itemAtIndex:0];
[browserItem setTarget:self];
[browserItem setAction:@selector(nullAction:)];
[browserItem setRepresentedObject:pathString];
}
// IE
pathString = [[NSString stringWithString:@"~/Library/Preferences/Explorer/Favorites.html"] stringByStandardizingPath];
if ([fm fileExistsAtPath:pathString]) {
[mBrowserListButton insertItemWithTitle:@"Internet Explorer" atIndex:0];
browserItem = [mBrowserListButton itemAtIndex:0];
[browserItem setTarget:self];
[browserItem setAction:@selector(nullAction:)];
[browserItem setRepresentedObject:pathString];
}
// Safari
pathString = [[NSString stringWithString:@"~/Library/Safari/Bookmarks.plist"] stringByStandardizingPath];
if ([fm fileExistsAtPath:pathString]) {
[mBrowserListButton insertItemWithTitle:@"Safari" atIndex:0];
browserItem = [mBrowserListButton itemAtIndex:0];
[browserItem setTarget:self];
[browserItem setAction:@selector(nullAction:)];
[browserItem setRepresentedObject:pathString];
}
[mBrowserListButton selectItemAtIndex:0];
[mBrowserListButton synchronizeTitleAndSelectedItem];
}
// keeps browsers turned on
-(IBAction) nullAction:(id)aSender
{
}
-(IBAction) cancel:(id)aSender
{
[NSApp stopModal];
[NSApp endSheet:[self window]];
[[self window] orderOut:self];
}
-(IBAction) import:(id)aSender
{
[NSApp stopModal];
[NSApp endSheet:[self window]];
[[self window] orderOut:self];
NSMenuItem *selectedItem = [mBrowserListButton selectedItem];
BookmarkFolder *importFolder = [[[BookmarkManager sharedBookmarkManager] rootBookmarks] addBookmarkFolder];
NSString *titleString;
if ([[selectedItem title] isEqualToString:@"Internet Explorer"])
titleString = [[NSString alloc] initWithString:NSLocalizedString(@"Imported IE Favorites",@"Imported IE Favorites")];
else
titleString = [[NSString alloc] initWithFormat:NSLocalizedString(@"Imported %@ Bookmarks",@"Imported %@ Bookmarks"),[selectedItem title]];
[importFolder setTitle:titleString];
[titleString release];
[[BookmarkManager sharedBookmarkManager] importBookmarks:[selectedItem representedObject] intoFolder:importFolder];
}
-(IBAction) loadOpenPanel:(id)aSender
{
[NSApp stopModal];
[NSApp endSheet:[self window]];
[[self window] orderOut:self];
NSOpenPanel* openPanel = [NSOpenPanel openPanel];
[openPanel setCanChooseFiles: YES];
[openPanel setCanChooseDirectories: NO];
[openPanel setAllowsMultipleSelection: NO];
NSArray* array = [NSArray arrayWithObjects: @"htm",@"html",@"xml", @"plist",nil];
int result = [openPanel runModalForDirectory: nil
file: nil
types: array];
if (result == NSOKButton) {
NSString *pathToFile = [[openPanel filenames] objectAtIndex:0];
BookmarkManager *bm = [BookmarkManager sharedBookmarkManager];
BookmarkFolder *importFolder = [[bm rootBookmarks] addBookmarkFolder];
[importFolder setTitle:NSLocalizedString(@"Imported Bookmarks",@"Imported Bookmarks")];
[bm importBookmarks:pathToFile intoFolder:importFolder];
}
}
@end

Просмотреть файл

@ -1,49 +1,73 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the 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/
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
* 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 the Mozilla browser.
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2002 Netscape Communications Corporation. All
* Rights Reserved.
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Goodger <ben@netscape.com> (Original Author)
* Simon Fraser <sfraser@netscape.com>
* David Haas <haasd@cae.wisc.edu>
*/
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import <AppKit/AppKit.h>
#import "BookmarksService.h"
#import "BookmarksClient.h"
@class BookmarkItem;
@interface BookmarkInfoController : NSWindowController<BookmarksClient>
{
IBOutlet NSTextField* mNameField;
IBOutlet NSTextField* mLocationField;
IBOutlet NSTextField* mKeywordField;
IBOutlet NSTextField* mDescriptionField;
IBOutlet NSTextField* mNameLabel;
IBOutlet NSTextField* mLocationLabel;
IBOutlet NSTextField* mKeywordLabel;
IBOutlet NSTextField* mDescriptionLabel;
IBOutlet NSView* mVariableFieldsContainer;
IBOutlet NSTabView* mTabView;
IBOutlet NSTextField* mBookmarkNameField;
IBOutlet NSTextField* mBookmarkLocationField;
IBOutlet NSTextField* mBookmarkKeywordField;
IBOutlet NSTextField* mBookmarkDescField;
IBOutlet NSTextField* mFolderNameField;
IBOutlet NSTextField* mFolderKeywordField;
IBOutlet NSTextField* mFolderKeywordLabel;
IBOutlet NSTextField* mFolderDescField;
IBOutlet NSTextField* mLastVisitField;
IBOutlet NSTextField* mStatusField;
IBOutlet NSTextField* mNumberVisitsField;
IBOutlet NSButton* mDockMenuCheckbox;
IBOutlet NSButton* mTabgroupCheckbox;
BookmarkItem* mBookmarkItem;
NSTextView* mFieldEditor;
IBOutlet NSButton* mTabgroupCheckbox;
IBOutlet NSButton* mDockMenuCheckbox;
IBOutlet NSButton* mClearNumberVisitsButton;
NSTabViewItem *mBookmarkInfoTabView;
NSTabViewItem *mBookmarkUpdateTabView;
NSTabViewItem *mFolderInfoTabView;
BookmarkItem *mBookmarkItem;
NSTextView *mFieldEditor;
}
+ (id)sharedBookmarkInfoController;
@ -52,7 +76,8 @@
-(void)setBookmark:(BookmarkItem*)aBookmark;
-(BookmarkItem*)bookmark;
- (IBAction)dockMenuCheckboxClicked:(id)sender;
- (IBAction)tabGroupCheckboxClicked:(id)sender;
- (IBAction)dockMenuCheckboxClicked:(id)sender;
- (IBAction)clearVisitCount:(id)sender;
@end

Просмотреть файл

@ -24,17 +24,17 @@
*/
#import "NSString+Utils.h"
#import "BookmarkInfoController.h"
#import "Bookmark.h"
#import "BookmarkFolder.h"
#include "nsIContent.h"
// determined through weeks of trial and error
#define kMaxLengthOfWindowTitle 49
@interface BookmarkInfoController(Private)
- (void)showUIElementPair: (id)aLabel control: (id) aControl;
- (void)hideUIElementPair: (id)aLabel control: (id) aControl;
- (void)commitChanges:(id)sender;
- (BOOL)commitField:(id)textField toProperty:(nsIAtom*)propertyAtom;
- (void)updateUI:(BookmarkItem *)anItem;
@end;
@ -48,7 +48,6 @@ static BookmarkInfoController *sharedBookmarkInfoController = nil;
if (!sharedBookmarkInfoController) {
sharedBookmarkInfoController = [[BookmarkInfoController alloc] initWithWindowNibName:@"BookmarkInfoPanel"];
}
return sharedBookmarkInfoController;
}
@ -66,26 +65,31 @@ static BookmarkInfoController *sharedBookmarkInfoController = nil;
mFieldEditor = [[NSTextView alloc] init];
[mFieldEditor setAllowsUndo:YES];
[mFieldEditor setFieldEditor:YES];
}
return self;
}
- (void)awakeFromNib
- (void)windowDidLoad
{
// keep a ref so that we can remove and add to the its superview with impunity
[mNameField retain];
[mLocationField retain];
[mKeywordField retain];
[mDescriptionField retain];
[mNameLabel retain];
[mLocationLabel retain];
[mKeywordLabel retain];
[mDescriptionLabel retain];
[mDockMenuCheckbox retain];
[mFolderKeywordField retain];
[mFolderKeywordLabel retain];
[mTabgroupCheckbox retain];
[[BookmarksManager sharedBookmarksManager] addBookmarksClient:self];
// find the TabViewItems & retain them, too. Like to do this
// in IB, but just doesn't want to connect. So do it here.
int tabIndex = [mTabView indexOfTabViewItemWithIdentifier:@"bminfo"];
mBookmarkInfoTabView = [[mTabView tabViewItemAtIndex:tabIndex] retain];
tabIndex = [mTabView indexOfTabViewItemWithIdentifier:@"bmupdate"];
mBookmarkUpdateTabView = [[mTabView tabViewItemAtIndex:tabIndex] retain];
tabIndex = [mTabView indexOfTabViewItemWithIdentifier:@"folinfo"];
mFolderInfoTabView = [[mTabView tabViewItemAtIndex:tabIndex] retain];
// it would be nice to do this in IB, but I can't make it connect.
[mBookmarkInfoTabView setInitialFirstResponder:mBookmarkNameField];
[mFolderInfoTabView setInitialFirstResponder:mFolderNameField];
[mBookmarkUpdateTabView setInitialFirstResponder:mClearNumberVisitsButton];
// Generic notifications for Bookmark Client - only care if there's a deletion
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:@selector(bookmarkRemoved:) name:BookmarkFolderDeletionNotification object:nil];
}
-(void)dealloc
@ -94,21 +98,16 @@ static BookmarkInfoController *sharedBookmarkInfoController = nil;
if (self == sharedBookmarkInfoController)
sharedBookmarkInfoController = nil;
[[BookmarksManager sharedBookmarksManagerDontAlloc] removeBookmarksClient:self];
[[NSNotificationCenter defaultCenter] removeObserver:self];
[mBookmarkItem release];
mBookmarkItem = nil;
[mFieldEditor release];
[mNameField release];
[mLocationField release];
[mKeywordField release];
[mDescriptionField release];
[mNameLabel release];
[mLocationLabel release];
[mKeywordLabel release];
[mDescriptionLabel release];
[mDockMenuCheckbox release];
[mFolderKeywordField release];
[mFolderKeywordLabel release];
[mTabgroupCheckbox release];
[mBookmarkInfoTabView release];
[mBookmarkUpdateTabView release];
[mFolderInfoTabView release];
[super dealloc];
}
@ -120,160 +119,221 @@ static BookmarkInfoController *sharedBookmarkInfoController = nil;
-(void)windowDidBecomeKey:(NSNotification*) aNotification
{
[[self window] makeFirstResponder:mNameField];
NSTabViewItem *tabViewItem = [mTabView selectedTabViewItem];
if (tabViewItem == mBookmarkInfoTabView)
[[self window] makeFirstResponder:mBookmarkNameField];
else if (tabViewItem == mFolderInfoTabView)
[[self window] makeFirstResponder:mFolderNameField];
else if (tabViewItem == mBookmarkUpdateTabView)
[[self window] makeFirstResponder:mClearNumberVisitsButton];
}
-(void)windowDidResignKey:(NSNotification*) aNotification
{
[[self window] makeFirstResponder:[self window]];
if (![[self window] isVisible])
mBookmarkItem = nil;
if (![[self window] isVisible])
[self setBookmark:nil];
}
- (void)windowWillClose:(NSNotification *)aNotification
{
[self commitChanges:nil];
mBookmarkItem = nil;
[self setBookmark:nil];
}
- (void)commitChanges:(id)changedField
{
if (![mBookmarkItem contentNode])
return;
BOOL changed = NO;
// Name
if ((!changedField && [mNameField superview]) || changedField == mNameField)
changed |= [self commitField:mNameField toProperty:BookmarksService::gNameAtom];
// Location
if ((!changedField && [mLocationField superview]) || changedField == mLocationField)
changed |= [self commitField:mLocationField toProperty:BookmarksService::gHrefAtom];
// Keyword
if ((!changedField && [mKeywordField superview]) || changedField == mKeywordField)
changed |= [self commitField:mKeywordField toProperty:BookmarksService::gKeywordAtom];
// Description
if ((!changedField && [mDescriptionField superview]) || changedField == mDescriptionField)
changed |= [self commitField:mDescriptionField toProperty:BookmarksService::gDescriptionAtom];
[[mFieldEditor undoManager] removeAllActions];
if (changed)
[mBookmarkItem itemChanged:YES];
}
// return YES if changed
- (BOOL)commitField:(id)textField toProperty:(nsIAtom*)propertyAtom
{
NSString* newValue = [textField stringValue];
NSString* oldValue = [mBookmarkItem getAttributeValue:propertyAtom];
if (![newValue isEqualToString:oldValue])
{
[mBookmarkItem setAttribute:propertyAtom toValue:newValue];
return YES;
NSTabViewItem *tabViewItem = [mTabView selectedTabViewItem];
BOOL isBookmark;
if ((isBookmark = [mBookmarkItem isKindOfClass:[Bookmark class]])) {
if ([(Bookmark *)mBookmarkItem isSeparator] || ![[mBookmarkItem parent] isKindOfClass:[BookmarkItem class]])
return;
}
return NO;
if (!changedField) {
if ((tabViewItem == mBookmarkInfoTabView) && isBookmark) {
[mBookmarkItem setTitle:[mBookmarkNameField stringValue]];
[mBookmarkItem setDescription:[mBookmarkDescField stringValue]];
[mBookmarkItem setKeyword:[mBookmarkKeywordField stringValue]];
[(Bookmark *)mBookmarkItem setUrl:[mBookmarkLocationField stringValue]];
}
else if (tabViewItem == mFolderInfoTabView && !isBookmark) {
[mBookmarkItem setTitle:[mFolderNameField stringValue]];
[mBookmarkItem setDescription:[mFolderDescField stringValue]];
if ([(BookmarkFolder *)mBookmarkItem isGroup])
[mBookmarkItem setKeyword:[mFolderKeywordField stringValue]];
}
}
else if ((changedField == mBookmarkNameField) || (changedField == mFolderNameField))
[mBookmarkItem setTitle:[changedField stringValue]];
else if ((changedField == mBookmarkKeywordField) || (changedField == mFolderKeywordField))
[mBookmarkItem setKeyword:[changedField stringValue]];
else if ((changedField == mBookmarkDescField) || (changedField == mFolderDescField))
[mBookmarkItem setDescription:[changedField stringValue]];
else if ((changedField == mBookmarkLocationField) && isBookmark)
[(Bookmark *)mBookmarkItem setUrl:[changedField stringValue]];
[[mFieldEditor undoManager] removeAllActions];
}
- (IBAction)dockMenuCheckboxClicked:(id)sender
// there's a bug on first load. I don't know why. But this fixes it, so I'll leave it in.
-(IBAction)showWindow:(id)sender
{
if ([sender state] == NSOnState)
BookmarksService::SetDockMenuRoot([mBookmarkItem contentNode]);
else
BookmarksService::SetDockMenuRoot(NULL);
[self updateUI:mBookmarkItem];
[super showWindow:sender];
}
- (IBAction)tabGroupCheckboxClicked:(id)sender
{
[mBookmarkItem setIsGroup:[sender state] == NSOnState];
[mBookmarkItem itemChanged:YES];
if ([mBookmarkItem isKindOfClass:[BookmarkFolder class]])
[(BookmarkFolder *)mBookmarkItem setIsGroup:[sender state] == NSOnState];
}
- (IBAction)dockMenuCheckboxClicked:(id)sender
{
if ([mBookmarkItem isKindOfClass:[BookmarkFolder class]]) {
[(BookmarkFolder *)mBookmarkItem setIsDockMenu:([sender state] == NSOnState)];
[mDockMenuCheckbox setEnabled:NO];
}
}
- (IBAction)clearVisitCount:(id)sender
{
if ([mBookmarkItem isKindOfClass:[Bookmark class]])
[(Bookmark *)mBookmarkItem setNumberOfVisits:0];
[mNumberVisitsField setIntValue:0];
}
-(void)setBookmark: (BookmarkItem*) aBookmark
{
// See bug 154081 - don't show this window if Bookmark doesn't exist
// after fix - this should never happen unless disaster strikes.
if (![aBookmark contentNode])
return;
BOOL isGroup = [aBookmark isGroup];
BOOL isFolder = !isGroup && [aBookmark isFolder];
// First, Show/Hide the appropriate UI
if (isGroup)
{
[self showUIElementPair: mNameLabel control: mNameField];
[self hideUIElementPair: mLocationLabel control: mLocationField];
[self showUIElementPair: mKeywordLabel control: mKeywordField];
[self showUIElementPair: mDescriptionLabel control: mDescriptionField];
[mVariableFieldsContainer addSubview:mTabgroupCheckbox];
[mVariableFieldsContainer addSubview:mDockMenuCheckbox];
[mNameField setNextKeyView:mTabgroupCheckbox];
[mTabgroupCheckbox setNextKeyView:mDockMenuCheckbox];
[mDockMenuCheckbox setNextKeyView:mKeywordField];
[mKeywordField setNextKeyView:mDescriptionField];
[mTabgroupCheckbox setEnabled:![aBookmark isToobarRoot]];
// to avoid a hard-to-find bug, we do UI stuff before setting
if (aBookmark) {
[self updateUI:aBookmark];
[aBookmark retain];
}
else if (isFolder)
{
[self showUIElementPair: mNameLabel control: mNameField];
[self hideUIElementPair: mLocationLabel control: mLocationField];
[self hideUIElementPair: mKeywordLabel control: mKeywordField];
[self showUIElementPair: mDescriptionLabel control: mDescriptionField];
[mBookmarkItem release];
mBookmarkItem = aBookmark;
}
[mVariableFieldsContainer addSubview:mDockMenuCheckbox];
[mVariableFieldsContainer addSubview:mTabgroupCheckbox];
[mNameField setNextKeyView:mDockMenuCheckbox];
[mDockMenuCheckbox setNextKeyView:mTabgroupCheckbox];
[mTabgroupCheckbox setNextKeyView:mDescriptionField];
[mTabgroupCheckbox setEnabled:![aBookmark isToobarRoot]];
-(void)updateUI:(BookmarkItem *)aBookmark
{
if (aBookmark) {
//
// setup for bookmarks
//
int numTabs = [mTabView numberOfTabViewItems];
if ([aBookmark isKindOfClass:[Bookmark class]]) {
if (numTabs == 1) {
[mTabView removeTabViewItem:mFolderInfoTabView];
[mTabView setTabViewType:NSTopTabsBezelBorder];
[mTabView insertTabViewItem:mBookmarkInfoTabView atIndex:0];
[mTabView insertTabViewItem:mBookmarkUpdateTabView atIndex:1];
[mTabView selectLastTabViewItem:self];//have to do this to avoid "2 selected tabs" ugliness
[mTabView selectFirstTabViewItem:self];
}
else if (numTabs == 3) {
[mTabView removeTabViewItem:mFolderInfoTabView];
[mTabView selectFirstTabViewItem:self];
}
[mBookmarkNameField setStringValue: [aBookmark title]];
[mBookmarkDescField setStringValue: [aBookmark description]];
[mBookmarkKeywordField setStringValue: [aBookmark keyword]];
[mBookmarkLocationField setStringValue: [(Bookmark *)aBookmark url]];
[mNumberVisitsField setIntValue:[(Bookmark *)aBookmark numberOfVisits]];
[mLastVisitField setStringValue: [[(Bookmark *)aBookmark lastVisit] descriptionWithCalendarFormat:[[mLastVisitField formatter] dateFormat] timeZone:[NSTimeZone localTimeZone] locale:nil]];
NSString *statusString = nil;
unsigned status = [(Bookmark *)aBookmark status];
switch (status) {
case (kBookmarkOKStatus):
case (kBookmarkSpacerStatus):
statusString = NSLocalizedString(@"OK",@"OK");
break;
case (kBookmarkBrokenLinkStatus):
statusString = NSLocalizedString(@"Link Broken",@"Link Broken");
break;
case (kBookmarkMovedLinkStatus):
statusString = NSLocalizedString(@"Link has Moved",@"Link has Moved");
break;
case (kBookmarkServerErrorStatus):
statusString = NSLocalizedString(@"Server Unreachable",@"Server Unreachable");
break;
case (kBookmarkNeverCheckStatus):
statusString = NSLocalizedString(@"Uncheckable",@"Uncheckable");
break;
default:
statusString = [NSString string];
}
[mStatusField setStringValue:statusString];
// if it's parent is a smart folder or it's a menu separator,
// we turn off all the fields. if it isn't, then we turn them all on
id parent = [aBookmark parent];
if (([parent isKindOfClass:[BookmarkItem class]]) &&
(![parent isSmartFolder]) &&
(![(Bookmark *)aBookmark isSeparator]))
{
[mBookmarkNameField setEditable:YES];
[mBookmarkDescField setEditable:YES];
[mBookmarkKeywordField setEditable:YES];
[mBookmarkLocationField setEditable:YES];
} else
{
[mBookmarkNameField setEditable:NO];
[mBookmarkDescField setEditable:NO];
[mBookmarkKeywordField setEditable:NO];
[mBookmarkLocationField setEditable:NO];
}
}
//
// Folders
//
else if ([aBookmark isKindOfClass:[BookmarkFolder class]]) {
if (numTabs == 2) {
[mTabView removeTabViewItem:mBookmarkInfoTabView];
[mTabView removeTabViewItem:mBookmarkUpdateTabView];
[mTabView insertTabViewItem:mFolderInfoTabView atIndex:0];
[mTabView setTabViewType:NSNoTabsNoBorder];
}
else if (numTabs == 3) {
[mTabView removeTabViewItem:mBookmarkInfoTabView];
[mTabView removeTabViewItem:mBookmarkUpdateTabView];
[mTabView setTabViewType:NSNoTabsNoBorder];
}
NSView *superview = [mFolderKeywordField superview];
if ([(BookmarkFolder *)aBookmark isGroup]) {
if (!superview) {
superview = [mFolderNameField superview];
[superview addSubview:mFolderKeywordField];
[superview addSubview:mFolderKeywordLabel];
[mFolderNameField setNextKeyView:mFolderKeywordField];
}
[mTabgroupCheckbox setState:NSOnState];
}
else {
if (superview) {
[mFolderKeywordField removeFromSuperview];
[mFolderKeywordLabel removeFromSuperview];
[mFolderNameField setNextKeyView:mFolderDescField];
}
[mTabgroupCheckbox setState:NSOffState];
}
[mFolderNameField setStringValue: [aBookmark title]];
[mFolderDescField setStringValue: [aBookmark description]];
//
// we can't just unselect dock menu - we have to pick a new one
//
if ([(BookmarkFolder *)aBookmark isDockMenu]) {
[mDockMenuCheckbox setState:NSOnState];
[mDockMenuCheckbox setEnabled:NO];
} else {
[mDockMenuCheckbox setState:NSOffState];
[mDockMenuCheckbox setEnabled:YES];
}
}
// Header
NSMutableString *truncatedTitle = [NSMutableString stringWithString:[aBookmark title]];
[truncatedTitle truncateTo:kMaxLengthOfWindowTitle at:kTruncateAtEnd];
NSString* infoForString = [NSString stringWithFormat:NSLocalizedString(@"BookmarkInfoTitle", @"Info for "), truncatedTitle];
[[self window] setTitle: infoForString];
}
else
{
[self showUIElementPair: mNameLabel control: mNameField];
[self showUIElementPair: mLocationLabel control: mLocationField];
[self showUIElementPair: mKeywordLabel control: mKeywordField];
[self showUIElementPair: mDescriptionLabel control: mDescriptionField];
[mDockMenuCheckbox removeFromSuperview];
[mTabgroupCheckbox removeFromSuperview];
[mNameField setNextKeyView:mLocationField];
[mLocationField setNextKeyView:mKeywordField];
[mKeywordField setNextKeyView:mDescriptionField];
}
// Then, fill with appropriate values from Bookmarks
NSString* bookmarkName = [aBookmark name];
NSString* infoForString = [NSString stringWithFormat:NSLocalizedString(@"BookmarkInfoTitle", @"Info for "), bookmarkName];
[[self window] setTitle: infoForString];
if (isGroup)
{
[mDockMenuCheckbox setState:([aBookmark isDockMenuRoot] ? NSOnState : NSOffState)];
[mTabgroupCheckbox setState:NSOnState];
[mKeywordField setStringValue: [aBookmark keyword]];
}
else if (isFolder)
{
[mDockMenuCheckbox setState:([aBookmark isDockMenuRoot] ? NSOnState : NSOffState)];
[mTabgroupCheckbox setState:NSOffState];
}
else
{
[mKeywordField setStringValue: [aBookmark keyword]];
[mLocationField setStringValue: [aBookmark url]];
}
[mNameField setStringValue: bookmarkName];
[mDescriptionField setStringValue: [aBookmark descriptionString]];
mBookmarkItem = aBookmark;
}
-(BookmarkItem *)bookmark
@ -281,29 +341,6 @@ static BookmarkInfoController *sharedBookmarkInfoController = nil;
return mBookmarkItem;
}
-(void)showUIElementPair: (id)aLabel control:(id)aControl
{
if ([aLabel superview] == nil)
[mVariableFieldsContainer addSubview: aLabel];
if ([aControl superview] == nil)
[mVariableFieldsContainer addSubview: aControl];
// we need to resize the fields in case the user resized the window when they were hidden
NSRect containerBounds = [mVariableFieldsContainer bounds];
NSRect controlFrame = [aControl frame];
controlFrame.size.width = (containerBounds.size.width - controlFrame.origin.x - 20.0);
[aControl setFrame:controlFrame];
}
-(void)hideUIElementPair: (id)aLabel control:(id)aControl
{
if ([aLabel superview] != nil)
[aLabel removeFromSuperview];
if ([aControl superview] != nil)
[aControl removeFromSuperview];
}
-(NSText *)windowWillReturnFieldEditor:(NSWindow *)aPanel toObject:(id)aObject
{
@ -312,21 +349,21 @@ static BookmarkInfoController *sharedBookmarkInfoController = nil;
#pragma mark -
- (void)bookmarkAdded:(nsIContent*)bookmark inContainer:(nsIContent*)container isChangedRoot:(BOOL)isRoot
- (void)bookmarkAdded:(NSNotification *)aNote
{
}
- (void)bookmarkRemoved:(nsIContent*)bookmark inContainer:(nsIContent*)container isChangedRoot:(BOOL)isRoot
- (void)bookmarkRemoved:(NSNotification *)aNote
{
if ([mBookmarkItem contentNode] == bookmark)
mBookmarkItem = nil;
NSDictionary *dict = [aNote userInfo];
BookmarkItem *item = [dict objectForKey:BookmarkFolderChildKey];
if ((item == [self bookmark]) && ![item parent]) {
[self setBookmark:nil];
[[self window] close];
}
}
- (void)bookmarkChanged:(nsIContent*)bookmark
{
}
- (void)specialFolder:(EBookmarksFolderType)folderType changedTo:(nsIContent*)newFolderContent
- (void)bookmarkChanged:(NSNotification *)aNote
{
}

Просмотреть файл

@ -0,0 +1,86 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* David Haas <haasd@cae.wisc.edu>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
// superclass for Bookmark & BookmarkFolder.
// Basically here to aid in scripting support.
#import <Appkit/Appkit.h>
@interface BookmarkItem : NSObject <NSCopying>
{
id mParent; //subclasses will use a BookmarkFolder
NSString* mTitle;
NSString* mDescription;
NSString* mKeyword;
NSImage* mIcon;
}
// Setters/Getters
-(id) parent;
-(NSString *) title;
-(NSString *) description;
-(NSString *) keyword;
-(NSImage *) icon;
-(void) setParent:(id)aParent;
-(void) setTitle:(NSString *)aString;
-(void) setDescription:(NSString *)aString;
-(void) setKeyword:(NSString *)aKeyword;
-(void) setIcon:(NSImage *)aIcon;
// Status checks
-(BOOL) isChildOfItem:(BookmarkItem *)anItem;
// Notificaiton of Change
-(void) itemUpdatedNote; //right now, just on title & icon - for BookmarkButton & BookmarkMenu notes
// Methods called on startup for both bookmark & folder
-(void) refreshIcon;
// for reading/writing to disk - unimplemented in BookmarkItem.
-(BOOL) readNativeDictionary:(NSDictionary *)aDict;
-(BOOL) readSafariDictionary:(NSDictionary *)aDict;
-(BOOL) readCaminoXML:(CFXMLTreeRef)aTreeRef;
-(NSDictionary *)writeNativeDictionary;
-(NSString *)writeHTML:(unsigned)aPad;
@end

Просмотреть файл

@ -0,0 +1,210 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* David Haas <haasd@cae.wisc.edu>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import "BookmarkItem.h"
// Notifications
NSString *BookmarkItemChangedNotification = @"bi_cg";
@implementation BookmarkItem
//Initialization
-(id) init
{
if ((self = [super init]))
{
// NSString *tempString = [[NSString alloc] init];
mParent = NULL;
mTitle = [[NSString alloc] init];
mKeyword = [[NSString alloc] init];
mDescription = [[NSString alloc] init];
// if we set the icon here, we will get a memory leak. so don't.
// subclass will provide icon.
mIcon = NULL;
}
return self;
}
-(id) copyWithZone:(NSZone *)zone
{
//descend from NSObject - so don't call super
id doppleganger = [[[self class] allocWithZone:zone] init];
[doppleganger setTitle:[self title]];
[doppleganger setDescription:[self description]];
[doppleganger setKeyword:[self keyword]];
[doppleganger setParent:[self parent]];
[doppleganger setIcon:[self icon]];
return doppleganger;
}
-(void)dealloc
{
[mTitle release];
[mDescription release];
[mKeyword release];
[mIcon release];
[super dealloc];
}
// Basic properties
-(id) parent
{
return mParent;
}
-(NSString *) title
{
return mTitle;
}
-(NSString *) description
{
return mDescription;
}
-(NSString *) keyword
{
return mKeyword;
}
-(NSImage *)icon
{
return mIcon;
}
-(BOOL) isChildOfItem:(BookmarkItem *)anItem
{
if (![[self parent] isKindOfClass:[BookmarkItem class]])
return NO;
if ([self parent] == anItem)
return YES;
return [[self parent] isChildOfItem:anItem];
}
-(void) setParent:(id) aParent
{
mParent = aParent; // no reference on the parent, so it better not disappear on us.
}
-(void) setTitle:(NSString *)aTitle
{
if (!aTitle)
return;
[aTitle retain];
[mTitle release];
mTitle = aTitle;
[self itemUpdatedNote];
}
-(void) setDescription:(NSString *)aDescription
{
if (!aDescription)
return;
[aDescription retain];
[mDescription release];
mDescription = aDescription;
}
- (void) setKeyword:(NSString *)aKeyword
{
if (!aKeyword)
return;
[aKeyword retain];
[mKeyword release];
mKeyword = aKeyword;
}
-(void) setIcon:(NSImage *)aIcon
{
if (!aIcon)
return;
[aIcon retain];
[mIcon release];
mIcon = aIcon;
[self itemUpdatedNote];
}
-(void) itemUpdatedNote
{
NSNotification *note = [NSNotification notificationWithName:BookmarkItemChangedNotification object:self userInfo:nil];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc postNotification:note];
return;
}
// stub functions to avoid warning
-(void) refreshIcon
{
}
//Reading/writing to & from disk - all just stubs.
-(BOOL) readNativeDictionary:(NSDictionary *)aDict
{
return NO;
}
-(BOOL) readSafariDictionary:(NSDictionary *)aDict
{
return NO;
}
-(BOOL) readCaminoXML:(CFXMLTreeRef)aTreeRef
{
return NO;
}
-(NSDictionary *)writeNativeDictionary
{
return [NSDictionary dictionary];
}
-(NSString *)writeHTML:(unsigned)aPad
{
return [NSString string];
}
@end

Просмотреть файл

@ -0,0 +1,106 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* David Haas <haasd@cae.wisc.edu>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import <Appkit/Appkit.h>
#import "BookmarksClient.h"
@class BookmarkFolder;
@class BookmarkImportDlgController;
@class KindaSmartFolderManager;
@class RunLoopMessenger;
#define kBookmarkMenuContainerIndex 0
#define kToolbarContainerIndex 1
#define kHistoryContainerIndex 2
#define kTop10ContainerIndex 3
#define kBrokenBookmarkContainerIndex 4
#define kRendezvousContainerIndex 5
#define kAddressBookContainerIndex 6
// check 1 bookmark every 2 minutes, but only if we haven't been there in a day
#define kTimeSinceBookmarkLastChecked 86400.0
#define kTimeToCheckAnotherBookmark 120
@interface BookmarkManager : NSObject <BookmarksClient> {
BookmarkFolder *mRootBookmarks; // root bookmark object
KindaSmartFolderManager *mSmartFolderManager; //brains behind 4 smart folders
NSUndoManager *mUndoManager;// handles deletes, adds of bookmarks
BookmarkImportDlgController *mImportDlgController;
NSString *mPathToBookmarkFile; //exactly what it looks like
NSTimer *mUpdateTimer; //we don't actually retain this
}
// Class Methods & shutdown stuff
+ (void)startBookmarksManager:(RunLoopMessenger *)mainThreadRunLoopMessenger;
+ (BookmarkManager*)sharedBookmarkManager;
- (void)shutdown;
// Getters/Setters
-(BookmarkFolder *) rootBookmarks;
-(BookmarkFolder *) toolbarFolder;
-(BookmarkFolder *) bookmarkMenuFolder;
-(BookmarkFolder *) dockMenuFolder;
-(BookmarkFolder *) top10Folder;
-(BookmarkFolder *) brokenLinkFolder;
-(BookmarkFolder *) rendezvousFolder;
-(BookmarkFolder *) addressBookFolder;
-(BookmarkFolder *) historyFolder;
-(NSUndoManager *) undoManager;
-(void) setRootBookmarks:(BookmarkFolder *)anArray;
// Informational things
-(NSArray *)resolveBookmarksKeyword:(NSString *)keyword;
-(NSArray *)searchBookmarksForString:(NSString *)searchString;
-(unsigned) firstUserCollection;
-(BOOL) isDropValid:(NSArray *)items toFolder:(BookmarkFolder *)parent;
// Reading bookmark files
-(BOOL) readBookmarks;
-(void) startImportBookmarks;
-(void) importBookmarks:(NSString *)pathToFile intoFolder:(BookmarkFolder *)aFolder;
-(NSString *)decodedHTMLfile:(NSString *)pathToFile;
-(BOOL)readHTMLFile:(NSString *)pathToFile intoFolder:(BookmarkFolder *)aFolder;
-(BOOL)readCaminoXMLFile:(NSString *)pathToFile intoFolder:(BookmarkFolder *)aFolder;
-(BOOL)readPropertyListFile:(NSString *)pathToFile intoFolder:(BookmarkFolder *)aFolder;
// Writing bookmark files
-(void)writeHTMLFile:(NSString *)pathToFile;
-(void)writePropertyListFile:(NSString *)pathToFile;
@end

Просмотреть файл

@ -0,0 +1,813 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* David Haas <haasd@cae.wisc.edu>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsString.h"
#include "nsIContent.h"
#include "nsIFile.h"
#include "nsAppDirectoryServiceDefs.h"
#import "NSString+Utils.h"
#import "PreferenceManager.h"
#import "RunLoopMessenger.h"
#import "BookmarkManager.h"
#import "Bookmark.h"
#import "BookmarkFolder.h"
#import "BookmarkImportDlgController.h"
#import "KindaSmartFolderManager.h"
#import "MainController.h"
@interface BookmarkManager (Private)
- (void)setPathToBookmarkFile:(NSString *)aString;
- (void)setupSmartCollections;
- (void)delayedStartupItems;
- (void)writeBookmarks:(NSNotification *)note;
- (void)checkForUpdates:(NSTimer *)aTimer;
- (BookmarkFolder *)findDockMenuFolderInFolder:(BookmarkFolder *)aFolder;
- (Bookmark *)findABookmarkToCheckInFolder:(BookmarkFolder *)aFolder;
@end
@implementation BookmarkManager
static NSString *WriteBookmarkNotification = @"write_bms";
static BookmarkManager* gBookmarksManager = nil;
static NSLock *startupLock = nil;
static unsigned gFirstUserCollection = 0;
//
// Class Methods - we only need RunLoopMessenger for 10.1 Compat. On 10.2+, there
// are built-in methods for running something on the main thread.
//
+ (void)startBookmarksManager:(RunLoopMessenger *)mainThreadRunLoopMessenger
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
if (!gBookmarksManager && !startupLock)
{
startupLock = [[NSLock alloc] init];
NSLock *avoidRaceLock;
BookmarkManager *aManager = [[BookmarkManager alloc] init];
[startupLock lock];
gBookmarksManager = aManager;
avoidRaceLock = startupLock;
startupLock = nil;
[avoidRaceLock unlock];
[avoidRaceLock release];
[[NSApp delegate] setupBookmarkMenus:gBookmarksManager];
[mainThreadRunLoopMessenger target:gBookmarksManager performSelector:@selector(delayedStartupItems)];
}
[pool release];
}
+ (BookmarkManager*)sharedBookmarkManager
{
BookmarkManager *theManager;
[startupLock lock];
theManager = gBookmarksManager;
[startupLock unlock];
return theManager;
}
//
// Init, dealloc - better get inited on background thread.
//
- (id)init
{
if ((self = [super init]))
{
BookmarkFolder* root = [[BookmarkFolder alloc] init];
[root setParent:self];
[root setIsRoot:YES];
[root setTitle:NSLocalizedString(@"BookmarksRootName", @"")];
[self setRootBookmarks:root];
[root release];
if (![self readBookmarks]) {
// one of two things happened. we are importing off an old xml file
// for startup, OR we totally muffed reading the bookmarks. we'll hope
// it was the former.
if ([root count] > 0) {
// find the xml toolbar menu. it'll be in top level of bookmark menu folder
NSMutableArray *childArray = [[self bookmarkMenuFolder] childArray];
unsigned i, j=[childArray count];
id anObject;
for (i=0;i < j; i++) {
anObject = [childArray objectAtIndex:i];
if ([anObject isKindOfClass:[BookmarkFolder class]]) {
if ([(BookmarkFolder *)anObject isToolbar]) { //triumph!
[[self bookmarkMenuFolder] moveChild:anObject toBookmarkFolder:root atIndex:kToolbarContainerIndex];
break;
}
}
}
} else { //we are so totally screwed
BookmarkFolder *aFolder = [root addBookmarkFolder];
if ([root count] == 1) {
[aFolder setTitle:NSLocalizedString(@"Bookmark Menu",@"Bookmark Menu")];
aFolder = [root addBookmarkFolder];
}
[aFolder setTitle:NSLocalizedString(@"Bookmark Toolbar",@"Bookmark Toolbar")];
}
}
// setup special folders
[self setupSmartCollections];
mSmartFolderManager = [[KindaSmartFolderManager alloc] initWithBookmarkManager:self];
// don't do this until after we've read in the bookmarks
mUndoManager = [[NSUndoManager alloc] init];
// Generic notifications for Bookmark Client
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:@selector(bookmarkAdded:) name:BookmarkFolderAdditionNotification object:nil];
[nc addObserver:self selector:@selector(bookmarkRemoved:) name:BookmarkFolderDeletionNotification object:nil];
[nc addObserver:self selector:@selector(bookmarkChanged:) name:BookmarkItemChangedNotification object:nil];
[nc addObserver:self selector:@selector(writeBookmarks:) name:WriteBookmarkNotification object:nil];
}
return self;
}
-(void) dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
if (mUpdateTimer)
[mUpdateTimer invalidate]; //we don't retain this, so don't release it.
[mUndoManager release];
[mRootBookmarks release];
[mPathToBookmarkFile release];
[mSmartFolderManager release];
if (mImportDlgController)
[mImportDlgController release];
if (self == gBookmarksManager)
gBookmarksManager = nil;
[super dealloc];
}
- (void)delayedStartupItems
{
// check update status of 1 bookmark every 2 minutes.
mUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:kTimeToCheckAnotherBookmark target:self selector:@selector(checkForUpdates:) userInfo:nil repeats:YES];
[mSmartFolderManager postStartupInitialization:self];
[[[self toolbarFolder] objectAtIndex:0] itemUpdatedNote];//makes sure we have toolbar on 1st window
if ([[PreferenceManager sharedInstance] getBooleanPref:"browser.chrome.favicons" withSuccess:NULL])
[mRootBookmarks refreshIcon];
}
- (void)shutdown;
{
[self writeBookmarks:nil];
}
//
// smart collections, as of now, are Rendezvous, Address Book, Top 10 List, Broken Bookmarks,
// We also have history, but that just points to the real history stuff.
- (void)setupSmartCollections
{
NSArray *names = nil;
if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_1) //10.1
names = [[NSArray alloc] initWithObjects:
NSLocalizedString(@"History",@"History"),
NSLocalizedString(@"Top 10 List",@"Top 10 List"),
NSLocalizedString(@"Broken Bookmarks",@"Broken Bookmarks"),
nil];
else // 10.2 +
names = [[NSArray alloc] initWithObjects:
NSLocalizedString(@"History",@"History"),
NSLocalizedString(@"Top 10 List",@"Top 10 List"),
NSLocalizedString(@"Broken Bookmarks",@"Broken Bookmarks"),
NSLocalizedString(@"Rendezvous",@"Rendezvous"),
NSLocalizedString(@"Address Book",@"Address Book"),
nil];
gFirstUserCollection = [names count]+2;
unsigned i, j=[names count];
for (i=0; i < j; i++) {
BookmarkFolder *temp = [[BookmarkFolder alloc] init];
[temp setTitle:[names objectAtIndex:i]];
[temp setIsSmartFolder:YES];
[mRootBookmarks insertChild:temp atIndex:(i+2) isMove:NO];
[temp release];
}
[names release];
// set pretty icons
[[self historyFolder] setIcon:[NSImage imageNamed:@"historyicon"]];
[[self top10Folder] setIcon:[NSImage imageNamed:@"top10_icon"]];
[[self bookmarkMenuFolder] setIcon:[NSImage imageNamed:@"bookmarkmenu_icon"]];
[[self toolbarFolder] setIcon:[NSImage imageNamed:@"bookmarktoolbar_icon"]];
[[self rendezvousFolder] setIcon:[NSImage imageNamed:@"rendezvous_icon"]];
[[self addressBookFolder] setIcon:[NSImage imageNamed:@"addressbook_icon"]];
[[self brokenLinkFolder] setIcon:[NSImage imageNamed:@"brokenbookmark_icon"]];
}
//
// Getter/Setter methods
//
-(BookmarkFolder *) rootBookmarks
{
return mRootBookmarks;
}
-(BookmarkFolder *) dockMenuFolder
{
BookmarkFolder *folder = [self findDockMenuFolderInFolder:[self rootBookmarks]];
if (folder)
return folder;
else
return [self top10Folder];
}
- (BookmarkFolder *)findDockMenuFolderInFolder:(BookmarkFolder *)aFolder
{
NSEnumerator *enumerator = [[aFolder childArray] objectEnumerator];
id aKid;
BookmarkFolder *foundFolder = nil;
while ((!foundFolder) && (aKid = [enumerator nextObject])) {
if ([aKid isKindOfClass:[BookmarkFolder class]]) {
if ([(BookmarkFolder *)aKid isDockMenu])
return aKid;
else
foundFolder = [self findDockMenuFolderInFolder:aKid];
}
}
return foundFolder;
}
-(BookmarkFolder *)top10Folder
{
return [[self rootBookmarks] objectAtIndex:kTop10ContainerIndex];
}
-(BookmarkFolder *) brokenLinkFolder
{
return [[self rootBookmarks] objectAtIndex:kBrokenBookmarkContainerIndex];
}
-(BookmarkFolder *) toolbarFolder
{
return [[self rootBookmarks] objectAtIndex:kToolbarContainerIndex];
}
-(BookmarkFolder *) bookmarkMenuFolder
{
return [[self rootBookmarks] objectAtIndex:kBookmarkMenuContainerIndex];
}
-(BookmarkFolder *) historyFolder
{
return [[self rootBookmarks] objectAtIndex:kHistoryContainerIndex];
}
-(BookmarkFolder *) rendezvousFolder
{
if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_1)
return [[self rootBookmarks] objectAtIndex:kRendezvousContainerIndex];
else
return nil;
}
-(BookmarkFolder *) addressBookFolder
{
if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_1)
return [[self rootBookmarks] objectAtIndex:kAddressBookContainerIndex];
else
return nil;
}
-(NSUndoManager *) undoManager
{
return mUndoManager;
}
-(unsigned) firstUserCollection
{
return gFirstUserCollection;
}
- (void)setPathToBookmarkFile:(NSString *)aString
{
[aString retain];
[mPathToBookmarkFile release];
mPathToBookmarkFile = aString;
}
-(void) setRootBookmarks:(BookmarkFolder *)anArray
{
if (anArray != mRootBookmarks) {
[anArray retain];
[mRootBookmarks release];
mRootBookmarks = anArray;
}
}
-(NSArray *)resolveBookmarksKeyword:(NSString *)keyword
{
NSArray *resolvedArray = nil;
if (![keyword isEqualToString:@""])
resolvedArray = [[self rootBookmarks] resolveKeyword:keyword];
if (resolvedArray)
return resolvedArray;
return [NSArray arrayWithObject:keyword];
}
-(NSArray *)searchBookmarksForString:(NSString *)searchString
{
NSMutableArray *matchingArray = nil;
if ((searchString) && ![searchString isEqualToString:@""]) {
NSSet *matchingSet = [[self rootBookmarks] bookmarksWithString:searchString];
NSEnumerator *enumerator = [matchingSet objectEnumerator];
id aThingy;
matchingArray = [NSMutableArray array];
while ((aThingy = [enumerator nextObject]))
[matchingArray addObject:aThingy];
}
return matchingArray;
}
//
// every couple of minutes, this gets called
// it finds the first bookmark we haven't been to in 24 hours
// and makes sure it's still there
//
- (void)checkForUpdates:(NSTimer *)aTimer
{
Bookmark *bm = [self findABookmarkToCheckInFolder:[self rootBookmarks]];
if (bm)
[bm checkForUpdate];
}
-(Bookmark *)findABookmarkToCheckInFolder:(BookmarkFolder *)aFolder
{
NSEnumerator *enumerator = [[aFolder childArray] objectEnumerator];
id aKid;
Bookmark *foundBookmark = nil;
while ((!foundBookmark) && (aKid = [enumerator nextObject])) {
if ([aKid isKindOfClass:[Bookmark class]]) {
if (([(Bookmark *)aKid isCheckable]) &&
([[(Bookmark *)aKid lastVisit] timeIntervalSinceNow] < -kTimeSinceBookmarkLastChecked))
foundBookmark = aKid;
} else if ([aKid isKindOfClass:[BookmarkFolder class]])
foundBookmark = [self findABookmarkToCheckInFolder:aKid];
}
return foundBookmark;
}
//
// Drag & drop
//
-(BOOL) isDropValid:(NSArray *)items toFolder:(BookmarkFolder *)parent
{
// Enumerate through items, make sure we're not being dropped into
// a child OR ourself OR that the a bookmark or group is going into root bookmarks.
NSEnumerator *enumerator = [items objectEnumerator];
id aBookmark;
while ((aBookmark = [enumerator nextObject])) {
if ([aBookmark isKindOfClass:[BookmarkFolder class]]) {
if (aBookmark == parent)
return NO;
if ((parent == [self rootBookmarks]) && [(BookmarkFolder *)aBookmark isGroup])
return NO;
} else if ([aBookmark isKindOfClass:[Bookmark class]]) {
if (parent == [self rootBookmarks])
return NO;
BookmarkFolder *menuFolder = [self bookmarkMenuFolder];
if ([aBookmark isSeparator] &&
((![parent isChildOfItem:menuFolder]) && (parent != menuFolder)))
return NO;
}
if ([parent isChildOfItem:aBookmark])
return NO;
}
return YES;
}
#pragma mark -
//
// BookmarkClient protocol - so we know when to write out
//
- (void)bookmarkAdded:(NSNotification *)note
{
[self bookmarkChanged:nil];
}
- (void)bookmarkRemoved:(NSNotification *)note
{
[self bookmarkChanged:nil];
}
- (void)bookmarkChanged:(NSNotification *)aNote
{
NSNotificationQueue* nq = [NSNotificationQueue defaultQueue];
NSNotification *note = [NSNotification notificationWithName:WriteBookmarkNotification object:self userInfo:nil];
[nq enqueueNotification:note postingStyle:NSPostASAP coalesceMask:NSNotificationCoalescingOnName forModes:[NSArray arrayWithObject:NSDefaultRunLoopMode]];
}
- (void)writeBookmarks:(NSNotification *)note
{
[self writePropertyListFile:mPathToBookmarkFile];
}
#pragma mark -
//
// Reading/Importing bookmark files
//
-(BOOL) readBookmarks
{
nsCOMPtr<nsIFile> aDir;
NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(aDir));
if (!aDir) return NO; // should be smarter
nsCAutoString aDirPath;
nsresult rv = aDir->GetNativePath(aDirPath);
if (NS_FAILED(rv)) return NO; // should be smarter.
NSString *profileDir = [NSString stringWithUTF8String:aDirPath.get()];
//
// figure out where Bookmarks.plist is and store it as mPathToBookmarkFile
// if there is a Bookmarks.plist, read it
// if there isn't a Bookmarks.plist, but there is a bookmarks.xml, read it.
// if there isn't either, move default Bookmarks.plist to profile dir & read it.
//
NSFileManager *fM = [NSFileManager defaultManager];
NSString *bookmarkPath = [profileDir stringByAppendingPathComponent:@"bookmarks.plist"];
[self setPathToBookmarkFile:bookmarkPath];
if ([fM isReadableFileAtPath:bookmarkPath]) {
if ([self readPropertyListFile:bookmarkPath intoFolder:[self rootBookmarks]])
return YES; // triumph!
} else if ([fM isReadableFileAtPath:[profileDir stringByAppendingPathComponent:@"bookmarks.xml"]]){
BookmarkFolder *aFolder = [[self rootBookmarks] addBookmarkFolder];
[aFolder setTitle:NSLocalizedString(@"Bookmark Menu",@"Bookmark Menu")];
if ([self readCaminoXMLFile:[profileDir stringByAppendingPathComponent:@"bookmarks.xml"] intoFolder:[self bookmarkMenuFolder]])
return NO; // triumph! - will do post processing in init
} else {
NSString *defaultBookmarks = [[NSBundle mainBundle] pathForResource:@"bookmarks" ofType:@"plist"];
if ([fM copyPath:defaultBookmarks toPath:bookmarkPath handler:nil]) {
if ([self readPropertyListFile:bookmarkPath intoFolder:[self rootBookmarks]])
return YES; //triumph!
}
}
// if we're here, we've had a problem
NSString *alert = NSLocalizedString(@"CorruptedBookmarksAlert",@"");
NSString *message = NSLocalizedString(@"CorruptedBookmarksMsg",@"");
NSString *okButton = NSLocalizedString(@"OKButtonText",@"");
NSRunAlertPanel(alert, message, okButton, nil, nil);
return NO;
}
-(void) startImportBookmarks
{
if (!mImportDlgController)
mImportDlgController = [[BookmarkImportDlgController alloc] initWithWindowNibName:@"BookmarkImportDlg"];
[mImportDlgController buildAvailableFileList];
[NSApp beginSheet:[mImportDlgController window]
modalForWindow:[[NSApp delegate] getFrontmostBrowserWindow]
modalDelegate:nil
didEndSelector:nil
contextInfo:nil];
}
-(void) importBookmarks:(NSString *)pathToFile intoFolder:(BookmarkFolder *)aFolder
{
//I feel dirty doing it this way. But we'll check file extension
//to figure out how to handle this. Damn you, Steve Jobs!!
NSUndoManager *undoManager =[self undoManager];
[undoManager beginUndoGrouping];
BOOL success = NO;
NSString *extension =[pathToFile pathExtension];
if ([extension isEqualToString:@"html"] || [extension isEqualToString:@"htm"])
success = [self readHTMLFile:pathToFile intoFolder:aFolder];
else if ([extension isEqualToString:@"xml"])
success = [self readCaminoXMLFile:pathToFile intoFolder:aFolder];
else if ([extension isEqualToString:@"plist"] || !success)
success = [self readPropertyListFile:pathToFile intoFolder:aFolder];
// we don't know the extension, or we failed to load. we'll take another
// crack at it trying everything we know.
if (!success) {
success = [self readHTMLFile:pathToFile intoFolder:aFolder];
if (!success)
[self readCaminoXMLFile:pathToFile intoFolder:aFolder];
}
[[undoManager prepareWithInvocationTarget:[self rootBookmarks]] deleteChild:aFolder];
[undoManager endUndoGrouping];
[undoManager setActionName:NSLocalizedString(@"Import Bookmarks",@"Import Bookmarks")];
}
// spits out html file as NSString with proper encoding. it's pretty shitty, frankly.
-(NSString *)decodedHTMLfile:(NSString *)pathToFile
{
NSData* fileAsData = [[NSData alloc] initWithContentsOfFile:pathToFile];
if (!fileAsData) {
NSLog(@"decodedHTMLfile: file %@ cannot be read.",pathToFile);
return nil;
}
// we're gonna assume for now it's ascii and hope for the best.
// i'm doing this because I think we can always read it in as ascii,
// while it might fail if we assume default system encoding. i don't
// know this for sure. but we'll have to do 2 decodings. big whoop.
NSString *fileString = [[NSString alloc] initWithData:fileAsData encoding:NSASCIIStringEncoding];
if (!fileString) {
NSLog(@"decodedHTMLfile: file %@ doesn't want to become a string. Exiting.",pathToFile);
[fileAsData release];
return nil;
}
// Create a dictionary with possible encodings. As I figure out more possible encodings,
// I'll add them to the dictionary.
NSString *utfdash8Key = @"content=\"text/html; charset=utf-8" ;
NSString *xmacromanKey = @"content=\"text/html; charset=x-mac-roman";
NSString *xmacsystemKey = @"CONTENT=\"text/html; charset=X-MAC-SYSTEM";
NSDictionary *encodingDict = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithUnsignedInt:NSUTF8StringEncoding],utfdash8Key,
[NSNumber numberWithUnsignedInt:NSMacOSRomanStringEncoding],xmacromanKey,
[NSNumber numberWithUnsignedInt:[NSString defaultCStringEncoding]],xmacsystemKey,
nil];
NSEnumerator *keyEnumerator = [encodingDict keyEnumerator];
id key;
NSRange aRange;
while ((key = [keyEnumerator nextObject])) {
aRange = [fileString rangeOfString:key options:NSCaseInsensitiveSearch];
if (aRange.location != NSNotFound) {
[fileString release];
fileString = [[NSString alloc] initWithData:fileAsData encoding:[[encodingDict objectForKey:key] unsignedIntValue]];
[fileAsData release];
return [fileString autorelease];
}
}
// if we're here, we don't have a clue as to the encoding. we'll guess default
[fileString release];
if ((fileString = [[NSString alloc] initWithData:fileAsData encoding:[NSString defaultCStringEncoding]])) {
NSLog(@"decodedHTMLFile: file %@ encoding unknown. Assume default and proceed.",pathToFile);
[fileAsData release];
return [fileString autorelease];
}
// we suck. this is almost certainly wrong, but oh well.
NSLog(@"decodedHTMLFile: file %@ encoding unknown, and NOT default. Use ASCII and proceed.",pathToFile);
fileString = [[NSString alloc] initWithData:fileAsData encoding:NSASCIIStringEncoding];
[fileAsData release];
return [fileString autorelease];
}
-(BOOL)readHTMLFile:(NSString *)pathToFile intoFolder:(BookmarkFolder *)aFolder;
{
// get file as NSString
NSString* fileAsString = [self decodedHTMLfile:pathToFile];
if (!fileAsString) {
NSLog(@"couldn't read file. bailing out");
return NO;
}
// Set up to scan the bookmark file
NSScanner *fileScanner = [[NSScanner alloc] initWithString:fileAsString];
BOOL isNetscape = YES;
// See if it's a netscape/IE style bookmark file, or omniweb
NSRange aRange = [fileAsString rangeOfString:@"<!DOCTYPE NETSCAPE-Bookmark-file-1>" options:NSCaseInsensitiveSearch];
if (aRange.location != NSNotFound) {
// netscape/IE setup - start after Title attribute
[fileScanner scanUpToString:@"</TITLE>" intoString:NULL];
[fileScanner setScanLocation:([fileScanner scanLocation] + 7)];
} else {
isNetscape = NO;
aRange = [fileAsString rangeOfString:@"<bookmarkInfo>" options:NSCaseInsensitiveSearch];
if (aRange.location != NSNotFound)
// omniweb setup - start at <bookmarkInfo>
[fileScanner scanUpToString:@"<bookmarkInfo>" intoString:NULL];
else {
NSLog(@"Unrecognized style of Bookmark File. Read fails.");
[fileScanner release];
return NO;
}
}
BookmarkFolder *currentArray = aFolder;
BookmarkItem *currentItem;
NSScanner *tokenScanner;
NSString *tokenTag, *tokenString, *tempItem;
unsigned scanIndex;
BOOL justSetTitle = NO;
// Scan through file. As we find a token, do something useful with it.
while (![fileScanner isAtEnd]) {
[fileScanner scanUpToString:@"<" intoString:&tokenString];
scanIndex = [fileScanner scanLocation];
if ((scanIndex+3) < [fileAsString length]) {
tokenTag = [[NSString alloc] initWithString:[fileAsString substringWithRange:NSMakeRange(scanIndex,3)]];
// now we pick out if it's something we want to save.
// check in a "most likely thing first" order
if (([tokenTag isEqualToString:@"<DT "]) || ([tokenTag isEqualToString:@"<dt "])) {
[fileScanner setScanLocation:([fileScanner scanLocation]+1)];
}
else if (([tokenTag isEqualToString:@"<P>"]) || ([tokenTag isEqualToString:@"<p>"])) {
[fileScanner setScanLocation:([fileScanner scanLocation]+1)];
}
else if (([tokenTag isEqualToString:@"<A "]) || ([tokenTag isEqualToString:@"<a "])) {
// adding a new bookmark to end of currentArray.
[fileScanner scanUpToString:@"</A>" intoString:&tokenString];
tokenScanner = [[NSScanner alloc] initWithString:tokenString];
[tokenScanner scanUpToString:@"href=\"" intoString:NULL];
[tokenScanner setScanLocation:([tokenScanner scanLocation]+6)];
[tokenScanner scanUpToString:@"\"" intoString:&tempItem];
currentItem = [currentArray addBookmark];
[(Bookmark *)currentItem setUrl:[tempItem stringByRemovingAmpEscapes]];
[tokenScanner scanUpToString:@">" intoString:NULL];
[currentItem setTitle:[[tokenString substringFromIndex:([tokenScanner scanLocation]+1)] stringByRemovingAmpEscapes]];
[tokenScanner release];
justSetTitle = YES;
[fileScanner setScanLocation:([fileScanner scanLocation]+1)];
}
else if (([tokenTag isEqualToString:@"<DD"]) || ([tokenTag isEqualToString:@"<dd"])) {
// add a description to current item
[fileScanner scanUpToString:@">" intoString:NULL];
[fileScanner setScanLocation:([fileScanner scanLocation]+1)];
[fileScanner scanUpToString:@"<" intoString:&tokenString];
[currentItem setDescription:[tokenString stringByRemovingAmpEscapes]];
justSetTitle = NO;
}
else if (([tokenTag isEqualToString:@"<H3"]) || ([tokenTag isEqualToString:@"<h3"])) {
[fileScanner scanUpToString:@"</H3>" intoString:&tokenString];
currentItem = [currentArray addBookmarkFolder];
currentArray = (BookmarkFolder *)currentItem;
tokenScanner = [[NSScanner alloc] initWithString:tokenString];
if (isNetscape) {
[tokenScanner scanUpToString:@">" intoString:NULL];
[currentItem setTitle:[[tokenString substringFromIndex:([tokenScanner scanLocation]+1)] stringByRemovingAmpEscapes]];
} else {
[tokenScanner scanUpToString:@"<a>" intoString:NULL];
[tokenScanner setScanLocation:([tokenScanner scanLocation]+3)];
[tokenScanner scanUpToString:@"</a>" intoString:&tempItem];
[currentItem setTitle:[tempItem stringByRemovingAmpEscapes]];
}
[tokenScanner release];
[fileScanner setScanLocation:([fileScanner scanLocation]+1)];
}
else if (([tokenTag isEqualToString:@"<DL"]) || ([tokenTag isEqualToString:@"<dl"])) {
[fileScanner setScanLocation:([fileScanner scanLocation]+1)];
}
else if (([tokenTag isEqualToString:@"</D"]) || ([tokenTag isEqualToString:@"</d"])) {
currentArray = (BookmarkFolder *)[currentArray parent];
[fileScanner setScanLocation:([fileScanner scanLocation]+1)];
}
else if (([tokenTag isEqualToString:@"<H1"]) || ([tokenTag isEqualToString:@"<h1"])) {
[fileScanner scanUpToString:@">" intoString:NULL];
[fileScanner scanUpToString:@"</H1>" intoString:NULL];
[fileScanner setScanLocation:([fileScanner scanLocation]+1)];
}
else if (([tokenTag isEqualToString:@"<BO"]) || ([tokenTag isEqualToString:@"<bo"])) {
//omniweb bookmark marker, no doubt
[fileScanner scanUpToString:@">" intoString:NULL];
[fileScanner setScanLocation:([fileScanner scanLocation]+1)];
}
else if (([tokenTag isEqualToString:@"</A"]) || ([tokenTag isEqualToString:@"</a"])) {
// some smartass has a description with </A in its title. Probably uses </H's, too. Dork.
// It will be just what was added, so append to string of last key.
// This this can only happen on older Camino html exports.
tempItem = [NSString stringWithString:[@"<" stringByAppendingString:[tokenString stringByRemovingAmpEscapes]]];
if (justSetTitle)
[currentItem setTitle:[[currentItem title] stringByAppendingString:tempItem]];
else
[currentItem setDescription:[[currentItem description] stringByAppendingString:tempItem]];
[fileScanner setScanLocation:([fileScanner scanLocation]+1)];
}
else if (([tokenTag isEqualToString:@"</H"]) || ([tokenTag isEqualToString:@"</h"])) {
// if it's not html, we'll include in previous text string
tempItem = [[NSString alloc] initWithString:[fileAsString substringWithRange:NSMakeRange(scanIndex,1)]];
if (([tempItem isEqualToString:@"</HT"]) || ([tempItem isEqualToString:@"</ht"]))
[fileScanner scanUpToString:@">" intoString:NULL];
else {
[tempItem release];
tempItem = [[NSString alloc] initWithString:[@"<" stringByAppendingString:[tokenString stringByRemovingAmpEscapes]]];
if (justSetTitle)
[currentItem setTitle:[[currentItem title] stringByAppendingString:tempItem]];
else
[currentItem setDescription:[[currentItem description] stringByAppendingString:tempItem]];
[fileScanner setScanLocation:([fileScanner scanLocation]+1)];
}
[tempItem release];
}
else { //beats me. just close the tag out and continue.
[fileScanner scanUpToString:@">" intoString:NULL];
}
[tokenTag release];
}
}
[fileScanner release];
return YES;
}
-(BOOL)readCaminoXMLFile:(NSString *)pathToFile intoFolder:(BookmarkFolder *)aFolder
{
NSURL* fileURL = [NSURL fileURLWithPath:pathToFile];
if (!fileURL) {
NSLog(@"URL creation failed");
return NO;
}
// Thanks, Apple, for example XML parsing code.
// Create CFXMLTree from file. This needs to be released later
CFXMLTreeRef XMLFileTree = CFXMLTreeCreateWithDataFromURL (kCFAllocatorDefault,
(CFURLRef)fileURL,
kCFXMLParserSkipWhitespace,
kCFXMLNodeCurrentVersion);
if (!XMLFileTree) {
NSLog(@"XMLTree creation failed");
return NO;
}
// process top level nodes. I think we'll find DTD
// before data - so only need to make 1 pass.
int count, index;
CFXMLTreeRef subFileTree;
CFXMLNodeRef bookmarkNode;
CFXMLDocumentTypeInfo *docTypeInfo;
CFURLRef dtdURL;
BOOL aBool;
count = CFTreeGetChildCount(XMLFileTree);
for (index=0;index < count;index++) {
subFileTree = CFTreeGetChildAtIndex(XMLFileTree,index);
if (subFileTree) {
bookmarkNode = CFXMLTreeGetNode(subFileTree);
if (bookmarkNode) {
switch (CFXMLNodeGetTypeCode(bookmarkNode)) {
// make sure it's Camino/Chimera DTD
case (kCFXMLNodeTypeDocumentType):
docTypeInfo = (CFXMLDocumentTypeInfo *)CFXMLNodeGetInfoPtr(bookmarkNode);
dtdURL = docTypeInfo->externalID.systemID;
if (![[(NSURL *)dtdURL absoluteString] isEqualToString:@"http://www.mozilla.org/DTDs/ChimeraBookmarks.dtd"]) {
NSLog(@"not a ChimeraBookmarks xml file. Bail");
CFRelease(XMLFileTree);
return NO;
}
break;
case (kCFXMLNodeTypeElement):
aBool = [aFolder readCaminoXML:subFileTree];
CFRelease (XMLFileTree);
return aBool;
break;
default:
break;
}
}
}
}
CFRelease(XMLFileTree);
NSLog(@"run through the tree and didn't find anything interesting. Bailed out");
return NO;
}
-(BOOL)readPropertyListFile:(NSString *)pathToFile intoFolder:aFolder
{
NSDictionary* dict = [NSDictionary dictionaryWithContentsOfFile:pathToFile];
// see if it's safari
if (![dict objectForKey:@"WebBookmarkType"])
return [aFolder readNativeDictionary:dict];
else
return [aFolder readSafariDictionary:dict];
}
//
// Writing bookmark files
//
- (void) writeHTMLFile:(NSString *)pathToFile
{
NSString *htmlString = [[self rootBookmarks] writeHTML:0];
if (![htmlString writeToFile:[pathToFile stringByStandardizingPath] atomically:YES])
NSLog(@"writeHTML: Failed to write file %@",pathToFile);
return;
}
-(void)writePropertyListFile:(NSString *)pathToFile
{
NSDictionary* dict = [[self rootBookmarks] writeNativeDictionary];
if (![dict writeToFile:[pathToFile stringByStandardizingPath] atomically:YES])
NSLog(@"writePropertyList: Failed to write file %@",pathToFile);
return;
}
@end

Просмотреть файл

@ -0,0 +1,54 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Chimera code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Simon Fraser <sfraser@netscape.com>
* David Haas <haasd@cae.wisc.edu>
*
* 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 <Appkit/Appkit.h>
#import "BookmarksClient.h"
@class BookmarkFolder;
@interface BookmarkMenu : NSObject <BookmarksClient>
{
NSMenu* mMenu; // retained
BookmarkFolder* mRootFolder;
int mFirstItemIndex;
BOOL mIsDockMenu;
}
- (id)initWithMenu:(NSMenu *)aMenu firstItem:(int)anIndex rootBookmarkFolder:(BookmarkFolder *)aFolder;
@end

Просмотреть файл

@ -0,0 +1,265 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Chimera code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Simon Fraser <sfraser@netscape.com>
* David Haas <haasd@cae.wisc.edu>
*
* 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 "BookmarkManager.h"
#import "BookmarkMenu.h"
#import "BookmarkFolder.h"
#import "Bookmark.h"
#import "NSString+Utils.h"
// Definitions
#define MENU_TRUNCATION_CHARS 60
@interface BookmarkMenu(Private)
- (NSMenu *)menu;
- (BookmarkFolder *)rootBookmarkFolder;
- (int)firstItemIndex;
- (void)setFirstItemIndex:(int)anIndex;
- (void)setRootBookmarkFolder:(BookmarkFolder *)anArray;
- (NSMenu *)locateMenuForItem:(BookmarkItem *)anItem;
- (void)constructMenu:(NSMenu *)menu forBookmarkFolder:(BookmarkFolder *)aFolder;
- (void)flushMenu;
- (void)addItem:(BookmarkItem *)anItem toMenu:(NSMenu *)aMenu atIndex:(int)aIndex;
- (void)dockMenuChanged:(NSNotification *)note;
@end
@implementation BookmarkMenu
// init & dealloc
- (id)initWithMenu:(NSMenu *)aMenu firstItem:(int)anIndex rootBookmarkFolder:(BookmarkFolder *)aFolder
{
if ((self = [super init]))
{
mMenu = [aMenu retain];
mFirstItemIndex = anIndex;
[self setRootBookmarkFolder:aFolder];
[self constructMenu:mMenu forBookmarkFolder:aFolder];
// Generic notifications for Bookmark Client
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:@selector(bookmarkAdded:) name:BookmarkFolderAdditionNotification object:nil];
[nc addObserver:self selector:@selector(bookmarkRemoved:) name:BookmarkFolderDeletionNotification object:nil];
[nc addObserver:self selector:@selector(bookmarkChanged:) name:BookmarkItemChangedNotification object:nil];
if (aFolder == [[BookmarkManager sharedBookmarkManager] dockMenuFolder])
[nc addObserver:self selector:@selector(dockMenuChanged:) name:BookmarkFolderDockMenuChangeNotificaton object:nil];
}
return self;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[mMenu release];
[mRootFolder release];
[super dealloc];
}
// Getters & setters
-(NSMenu *)menu
{
return mMenu;
}
-(BookmarkFolder *)rootBookmarkFolder
{
return mRootFolder;
}
-(int)firstItemIndex
{
return mFirstItemIndex;
}
-(void)setRootBookmarkFolder:(BookmarkFolder *)aFolder
{
[aFolder retain];
[mRootFolder release];
mRootFolder = aFolder;
}
-(void)setFirstItemIndex:(int)anIndex
{
mFirstItemIndex=anIndex;
}
//
// Utility methods
//
- (void)flushMenu
{
int firstItemIndex = [self firstItemIndex];
NSMenu *menu = [self menu];
while ([menu numberOfItems] > firstItemIndex)
[menu removeItemAtIndex:firstItemIndex];
}
- (void)constructMenu:(NSMenu *)menu forBookmarkFolder:(BookmarkFolder *)aFolder
{
unsigned i, childCount = [aFolder count];
for (i = 0; i < childCount; i++)
[self addItem:[aFolder objectAtIndex:i] toMenu:menu atIndex:i];
}
- (void)addItem:(BookmarkItem *)anItem toMenu:(NSMenu *)aMenu atIndex:(int)aIndex
{
NSMenuItem *menuItem;
NSString *title = [[anItem title] stringByTruncatingTo:MENU_TRUNCATION_CHARS at:kTruncateAtMiddle];
unsigned realIndex = aIndex;
if (aMenu == [self menu])
realIndex += [self firstItemIndex];
if ([anItem isKindOfClass:[Bookmark class]]) {
if (![(Bookmark *)anItem isSeparator]) { // normal bookmark
menuItem = [[NSMenuItem alloc] initWithTitle:title action: NULL keyEquivalent: @""];
[menuItem setTarget:[NSApp delegate]];
[menuItem setAction:@selector(openMenuBookmark:)];
[menuItem setImage:[anItem icon]];
} else {//separator
menuItem = [NSMenuItem separatorItem];
}
[aMenu insertItem:menuItem atIndex:realIndex];
} else if ([anItem isKindOfClass:[BookmarkFolder class]]){
if (![(BookmarkFolder *)anItem isGroup]) { //normal folder
menuItem = [[NSMenuItem alloc] initWithTitle:title action: NULL keyEquivalent: @""];
[aMenu insertItem:menuItem atIndex:realIndex];
[menuItem setImage: [anItem icon]];
NSMenu* subMenu = [[NSMenu alloc] initWithTitle:title];
[aMenu setSubmenu: subMenu forItem: menuItem];
[subMenu setAutoenablesItems: NO];
[self constructMenu:subMenu forBookmarkFolder:(BookmarkFolder *)anItem];
[subMenu release];
} else { //group
menuItem = [[NSMenuItem alloc] initWithTitle:title action: NULL keyEquivalent: @""];
[aMenu insertItem:menuItem atIndex:realIndex];
[menuItem setTarget:[NSApp delegate]];
[menuItem setAction:@selector(openMenuBookmark:)];
[menuItem setImage:[anItem icon]];
}
}
[menuItem setRepresentedObject:anItem];
if (![menuItem isSeparatorItem])
[menuItem release];
}
- (NSMenu *)locateMenuForItem:(BookmarkItem *)anItem
{
if (![anItem isKindOfClass:[BookmarkItem class]])
return nil; //make sure we haven't gone to top of menu item doesn't live in.
if (anItem == [self rootBookmarkFolder])
return [self menu];
NSMenu* parentMenu = [self locateMenuForItem:[anItem parent]];
if (parentMenu) {
int index = [parentMenu indexOfItemWithRepresentedObject:anItem];
if (index != -1) {
if ([anItem isKindOfClass:[BookmarkFolder class]]) {
NSMenuItem* childMenu = [parentMenu itemAtIndex:index];
return [childMenu submenu];
} else if ([anItem isKindOfClass:[Bookmark class]])
return parentMenu;
}
}
return nil;
}
#pragma mark -
// For the BookmarksClient Protocol
- (void)bookmarkAdded:(NSNotification *)note
{
BookmarkFolder *aFolder = [note object];
NSMenu* menu = nil;
if (aFolder == [self rootBookmarkFolder])
menu = [self menu];
else if (![aFolder isGroup])
menu = [self locateMenuForItem:aFolder];
if (menu) {
NSDictionary *dict = [note userInfo];
[self addItem:[dict objectForKey:BookmarkFolderChildKey] toMenu:menu atIndex:[[dict objectForKey:BookmarkFolderChildIndexKey] unsignedIntValue]];
}
}
- (void)bookmarkRemoved:(NSNotification *)note
{
BookmarkFolder *aFolder = [note object];
NSMenu* menu = nil;
if (aFolder == [self rootBookmarkFolder])
menu = [self menu];
else if (![aFolder isGroup])
menu = [self locateMenuForItem:aFolder];
if (menu) {
BookmarkItem *anItem = [[note userInfo] objectForKey:BookmarkFolderChildKey];
[menu removeItemAtIndex:[menu indexOfItemWithRepresentedObject:anItem]];
}
}
- (void)bookmarkChanged:(NSNotification *)note
{
BookmarkItem* anItem = [note object];
NSMenu *menu = nil;
BOOL isSeparator = NO;
if ([[self rootBookmarkFolder] isSmartFolder])
menu = [self menu];
else if ([anItem isKindOfClass:[Bookmark class]]) {
menu = [self locateMenuForItem:anItem];
isSeparator = [(Bookmark *)anItem isSeparator];
}
else if ([anItem isKindOfClass:[BookmarkFolder class]])
menu = [self locateMenuForItem:[anItem parent]];
if (menu) {
int index = [menu indexOfItemWithRepresentedObject:anItem];
if (index != -1) {
if (!isSeparator) {
NSMenuItem *menuItem = [menu itemAtIndex:index];
[menuItem setTitle:[[anItem title] stringByTruncatingTo:MENU_TRUNCATION_CHARS at:kTruncateAtMiddle]];
[menuItem setImage:[anItem icon]];
} else {
[menu removeItemAtIndex:index];
[menu insertItem:[NSMenuItem separatorItem] atIndex:index];
}
}
}
}
- (void)dockMenuChanged:(NSNotification *)note
{
BookmarkFolder *aFolder = [note object];
[self flushMenu];
[self setRootBookmarkFolder:aFolder];
[self constructMenu:[self menu] forBookmarkFolder:aFolder];
}
@end

Просмотреть файл

@ -0,0 +1,47 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Joe Hewitt <hewitt@netscape.com> (Original Author)
* David Haas <haasd@cae.wisc.edu>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import <AppKit/AppKit.h>
#import "ExtendedOutlineView.h"
@interface BookmarkOutlineView : ExtendedOutlineView
{
}
@end

Просмотреть файл

@ -0,0 +1,98 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Joe Hewitt <hewitt@netscape.com> (Original Author)
* David Haas <haasd@cae.wisc.edu>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import "BookmarkOutlineView.h"
#import "BookmarkFolder.h"
#import "Bookmark.h"
#import "NSArray+Utils.h"
@implementation BookmarkOutlineView
- (void)awakeFromNib
{
[self registerForDraggedTypes:[NSArray arrayWithObjects:@"MozURLType", @"MozBookmarkType", NSStringPboardType, NSURLPboardType, nil]];
}
- (void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation
{
if (operation == NSDragOperationDelete)
{
NSPasteboard* pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
NSArray* bookmarks = [NSArray pointerArrayFromDataArrayForMozBookmarkDrop:[pboard propertyListForType: @"MozBookmarkType"]];
if (bookmarks)
{
for (unsigned int i = 0; i < [bookmarks count]; ++i)
{
BookmarkItem* item = [bookmarks objectAtIndex:i];
[[item parent] deleteChild:item];
}
}
}
}
// don't edit URL field of folders or menu separators
- (void)_editItem:(id)dummy
{
id itemToEdit = [self itemAtRow:mRowToBeEdited];
if ([itemToEdit isKindOfClass:[BookmarkFolder class]]) {
if ((mColumnToBeEdited == [self columnWithIdentifier:@"url"]) ||
((![itemToEdit isGroup]) && (mColumnToBeEdited == [self columnWithIdentifier:@"keyword"]))) {
[super _cancelEditItem];
return;
}
} else if ([itemToEdit isKindOfClass:[Bookmark class]]) {
if ([(Bookmark *)itemToEdit isSeparator]) {
[super _cancelEditItem];
return;
}
}
[super _editItem:dummy];
}
- (unsigned int)draggingSourceOperationMaskForLocal:(BOOL)localFlag
{
if (localFlag)
return (NSDragOperationCopy | NSDragOperationGeneric | NSDragOperationMove);
return (NSDragOperationDelete | NSDragOperationGeneric);
}
@end

Просмотреть файл

@ -0,0 +1,73 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* David Hyatt <hyatt@apple.com> (Original Author)
* David Haas <haasd@cae.wisc.edu>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import <AppKit/AppKit.h>
#import "BookmarksClient.h"
@class BookmarkButton;
@class BookmarkItem;
@interface BookmarkToolbar : NSView<BookmarksClient>
{
NSMutableArray* mButtons;
BookmarkButton* mDragInsertionButton;
int mDragInsertionPosition;
BOOL mIsShowing;
BOOL mDrawBorder;
}
// Called to construct & edit the initial set of personal toolbar buttons.
-(void)buildButtonList;
-(void)addButton:(BookmarkItem*)aItem atIndex:(int)aIndex;
-(void)editButton:(BookmarkItem*)aItem;
-(void)removeButton:(BookmarkItem*)aItem;
// Called to lay out the buttons on the toolbar.
-(void)reflowButtons;
-(void)reflowButtonsStartingAtIndex: (int)aIndex;
-(BOOL)isShown;
-(void)setDrawBottomBorder:(BOOL)drawBorder;
-(void)showBookmarksToolbar: (BOOL)aShow;
-(IBAction)addFolder:(id)aSender;
@end

Просмотреть файл

@ -0,0 +1,592 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* David Hyatt <hyatt@apple.com> (Original Author)
* Kathy Brade <brade@netscape.com>
* David Haas <haasd@cae.wisc.edu>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import "BookmarkToolbar.h"
#import "CHBrowserService.h"
#import "BookmarkButton.h"
#import "BookmarkManager.h"
#import "BrowserWindowController.h"
#import "Bookmark.h"
#import "BookmarkFolder.h"
#import "NSArray+Utils.h"
#define CHInsertNone 0
#define CHInsertInto 1
#define CHInsertBefore 2
#define CHInsertAfter 3
@interface BookmarkToolbar(Private)
- (void)setButtonInsertionPoint:(id <NSDraggingInfo>)sender;
- (NSRect)insertionRectForButton:(NSView*)aButton position:(int)aPosition;
- (BookmarkButton*)makeNewButtonWithItem:(BookmarkItem*)aItem;
@end
@implementation BookmarkToolbar
- (id)initWithFrame:(NSRect)frame
{
if ( (self = [super initWithFrame:frame]) )
{
mButtons = [[NSMutableArray alloc] init];
mDragInsertionButton = nil;
mDragInsertionPosition = CHInsertNone;
mDrawBorder = YES;
[self registerForDraggedTypes:[NSArray arrayWithObjects:@"MozURLType", @"MozBookmarkType", NSStringPboardType, NSURLPboardType, nil]];
mIsShowing = YES;
// Generic notifications for Bookmark Client
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:@selector(bookmarkAdded:) name:BookmarkFolderAdditionNotification object:nil];
[nc addObserver:self selector:@selector(bookmarkRemoved:) name:BookmarkFolderDeletionNotification object:nil];
[nc addObserver:self selector:@selector(bookmarkChanged:) name:BookmarkItemChangedNotification object:nil];
}
return self;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[mButtons release];
[super dealloc];
}
- (void)drawRect:(NSRect)aRect
{
if (mDrawBorder)
{
[[NSColor controlShadowColor] set];
float height = [self bounds].size.height;
NSRectFill(NSMakeRect(aRect.origin.x, height - 1.0, aRect.size.width, height));
}
// The buttons will paint themselves. Just call our base class method.
[super drawRect: aRect];
// draw a separator at drag n drop insertion point if there is one
if (mDragInsertionPosition)
{
[[[NSColor controlShadowColor] colorWithAlphaComponent:0.6] set];
NSRectFill([self insertionRectForButton:mDragInsertionButton position:mDragInsertionPosition]);
}
}
-(void)buildButtonList
{
BookmarkFolder* toolbar = [[BookmarkManager sharedBookmarkManager] toolbarFolder];
for (unsigned int i = 0; i < [toolbar count]; i ++)
{
BookmarkButton* button = [self makeNewButtonWithItem:[toolbar objectAtIndex:i]];
[self addSubview: button];
[mButtons addObject: button];
}
if ([self isShown])
[self reflowButtons];
}
- (void)resetButtonList
{
int count = [mButtons count];
for (int i = 0; i < count; i++)
{
BookmarkButton* button = [mButtons objectAtIndex: i];
[button removeFromSuperview];
}
[mButtons removeAllObjects];
[self setNeedsDisplay:YES];
}
-(void)addButton:(BookmarkItem*)aItem atIndex:(int)aIndex
{
BookmarkButton* button = [self makeNewButtonWithItem:aItem];
[self addSubview: button];
[mButtons insertObject: button atIndex: aIndex];
if ([self isShown])
[self reflowButtonsStartingAtIndex: aIndex];
}
-(void)editButton:(BookmarkItem*)aItem
{
int count = [mButtons count];
for (int i = 0; i < count; i++)
{
BookmarkButton* button = [mButtons objectAtIndex: i];
if ([button BookmarkItem] == aItem)
{
[button setBookmarkItem: aItem];
if (count > i && [self isShown])
[self reflowButtonsStartingAtIndex: i];
break;
}
}
[self setNeedsDisplay:YES];
}
-(void)removeButton:(BookmarkItem*)aItem
{
int count = [mButtons count];
for (int i = 0; i < count; i++)
{
BookmarkButton* button = [mButtons objectAtIndex: i];
if ([button BookmarkItem] == aItem)
{
[mButtons removeObjectAtIndex: i];
[button removeFromSuperview];
if (count > i && [self isShown])
[self reflowButtonsStartingAtIndex: i];
break;
}
}
[self setNeedsDisplay:YES];
}
-(void)reflowButtons
{
[self reflowButtonsStartingAtIndex: 0];
}
#define kBookmarkButtonHeight 16.0
#define kMinBookmarkButtonWidth 16.0
#define kMaxBookmarkButtonWidth 150.0
#define kBookmarkButtonHorizPadding 2.0
#define kBookmarkButtonVerticalPadding 1.0
#define kBookmarkToolbarBottomPadding 1.0
-(void)reflowButtonsStartingAtIndex: (int)aIndex
{
if (![self isShown])
return;
// coordinates for this view are flipped, making it easier to lay out from top left
// to bottom right.
float oldHeight = [self frame].size.height;
int count = [mButtons count];
float curRowYOrigin = 0.0;
float curX = kBookmarkButtonHorizPadding;
for (int i = 0; i < count; i ++)
{
BookmarkButton* button = [mButtons objectAtIndex: i];
NSRect buttonRect;
if (i < aIndex)
{
buttonRect = [button frame];
curRowYOrigin = NSMinY(buttonRect) - kBookmarkButtonVerticalPadding;
curX = NSMaxX(buttonRect) + kBookmarkButtonHorizPadding;
}
else
{
[button sizeToFit];
float width = [button frame].size.width;
if (width > kMaxBookmarkButtonWidth)
width = kMaxBookmarkButtonWidth;
buttonRect = NSMakeRect(curX, curRowYOrigin + kBookmarkButtonVerticalPadding, width, kBookmarkButtonHeight);
curX += NSWidth(buttonRect) + kBookmarkButtonHorizPadding;
if (NSMaxX(buttonRect) > NSWidth([self bounds]))
{
curRowYOrigin += (kBookmarkButtonHeight + 2 * kBookmarkButtonVerticalPadding);
buttonRect = NSMakeRect(kBookmarkButtonHorizPadding, curRowYOrigin + kBookmarkButtonVerticalPadding, width, kBookmarkButtonHeight);
curX = NSWidth(buttonRect);
}
[button setFrame: buttonRect];
}
}
float computedHeight = curRowYOrigin + (kBookmarkButtonHeight + 2 * kBookmarkButtonVerticalPadding + kBookmarkToolbarBottomPadding);
// our size has changed, readjust our view's frame and the content area
if (computedHeight != oldHeight)
{
[super setFrame: NSMakeRect([self frame].origin.x, [self frame].origin.y + (oldHeight - computedHeight),
[self frame].size.width, computedHeight)];
[self setNeedsDisplay:YES];
// tell the superview to resize its subviews
[[self superview] resizeSubviewsWithOldSize:[[self superview] frame].size];
}
}
-(BOOL)isFlipped
{
return YES; // Use flipped coords, so we can layout out from top row to bottom row.
}
-(void)setFrame:(NSRect)aRect
{
NSRect oldFrame = [self frame];
[super setFrame:aRect];
if (oldFrame.size.width == aRect.size.width || aRect.size.height == 0)
return;
int count = [mButtons count];
int reflowStart = 0;
// find out where we need to start reflowing
for (int i = 0; i < count; i ++)
{
BookmarkButton* button = [mButtons objectAtIndex:i];
NSRect buttonFrame = [button frame];
if ((NSMaxX(buttonFrame) > NSMaxX(aRect)) || // we're overhanging the right
(NSMaxY(buttonFrame) > kBookmarkButtonHeight)) // we're on the second row
{
reflowStart = i;
break;
}
}
[self reflowButtonsStartingAtIndex:reflowStart];
}
-(BOOL)isShown
{
return mIsShowing;
}
-(void)setDrawBottomBorder:(BOOL)drawBorder
{
if (mDrawBorder != drawBorder)
{
mDrawBorder = drawBorder;
NSRect dirtyRect = [self bounds];
dirtyRect.origin.y = dirtyRect.size.height - 1.0;
dirtyRect.size.height = 1.0;
[self setNeedsDisplayInRect:dirtyRect];
}
}
//
// if the toolbar gets the message, we can only make a new folder.
// kinda dull. but we'll do this on the fly.
//
-(NSMenu*)menuForEvent:(NSEvent*)aEvent
{
NSMenu* myMenu = [[NSMenu alloc] initWithTitle:@"snookums"];
NSMenuItem *menuItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Create New Folder...",@"Create New Folder...") action:@selector(addFolder:) keyEquivalent:[NSString string]];
[menuItem setTarget:self];
[myMenu addItem:menuItem];
[menuItem release];
return [myMenu autorelease];
}
//
// context menu has only what we need
//
-(BOOL)validateMenuItem:(NSMenuItem*)aMenuItem
{
return YES;
}
-(IBAction)addFolder:(id)aSender
{
BookmarkFolder* toolbar = [[BookmarkManager sharedBookmarkManager] toolbarFolder];
BookmarkFolder* aFolder = [toolbar addBookmarkFolder];
[aFolder setTitle:NSLocalizedString(@"NewBookmarkFolder",@"New Folder")];
}
-(void)showBookmarksToolbar: (BOOL)aShow
{
mIsShowing = aShow;
if (!aShow)
{
[[self superview] setNeedsDisplayInRect:[self frame]];
NSRect newFrame = [self frame];
newFrame.origin.y += newFrame.size.height;
newFrame.size.height = 0;
[self setFrame: newFrame];
// tell the superview to resize its subviews
[[self superview] resizeSubviewsWithOldSize:[[self superview] frame].size];
}
else
{
[self reflowButtons];
[self setNeedsDisplay:YES];
}
}
- (void)setButtonInsertionPoint:(id <NSDraggingInfo>)sender
{
NSPoint dragLocation = [sender draggingLocation];
NSPoint superviewLoc = [[self superview] convertPoint:dragLocation fromView:nil]; // convert from window
NSButton* sourceButton = [sender draggingSource];
mDragInsertionButton = nil;
mDragInsertionPosition = CHInsertAfter;
NSView* foundView = [self hitTest:superviewLoc];
if (foundView && [foundView isMemberOfClass:[BookmarkButton class]])
{
BookmarkButton* targetButton = foundView;
BookmarkItem* targetItem = [targetButton BookmarkItem];
if ([targetItem isKindOfClass:[BookmarkFolder class]])
{
mDragInsertionButton = targetButton;
mDragInsertionPosition = CHInsertInto;
}
else if (targetButton != sourceButton)
{
NSPoint localLocation = [[self superview] convertPoint:superviewLoc toView:foundView];
mDragInsertionButton = targetButton;
if (localLocation.x < NSWidth([targetButton bounds]) / 2.0)
mDragInsertionPosition = CHInsertBefore;
else
mDragInsertionPosition = CHInsertAfter;
}
}
else
{
// throw it in at the end
mDragInsertionButton = ([mButtons count] > 0) ? [mButtons objectAtIndex:[mButtons count] - 1] : 0;
mDragInsertionPosition = CHInsertAfter;
}
}
- (BOOL)dropDestinationValid:(id <NSDraggingInfo>)sender
{
NSPasteboard* draggingPasteboard = [sender draggingPasteboard];
NSArray* types = [draggingPasteboard types];
BookmarkManager *bmManager = [BookmarkManager sharedBookmarkManager];
BookmarkFolder* toolbar = [bmManager toolbarFolder];
if (!toolbar)
return NO;
if ([types containsObject: @"MozBookmarkType"])
{
NSArray *draggedItems = [NSArray pointerArrayFromDataArrayForMozBookmarkDrop:[draggingPasteboard propertyListForType: @"MozBookmarkType"]];
BookmarkItem* destItem = nil;
int index = 0;
if (mDragInsertionPosition == CHInsertInto)
// drop onto folder
{
destItem = [mDragInsertionButton BookmarkItem];
index = 0;
}
else if (mDragInsertionPosition == CHInsertBefore ||
mDragInsertionPosition == CHInsertAfter) // drop onto toolbar
{
index = [mButtons indexOfObjectIdenticalTo:mDragInsertionButton];
if (mDragInsertionPosition == CHInsertAfter)
++index;
}
if (![bmManager isDropValid:draggedItems toFolder:toolbar])
return NO;
}
return YES;
}
// NSDraggingDestination ///////////
- (unsigned int)draggingEntered:(id <NSDraggingInfo>)sender
{
// we have to set the drag target before we can test for drop validation
[self setButtonInsertionPoint:sender];
if (![self dropDestinationValid:sender]) {
mDragInsertionButton = nil;
mDragInsertionPosition = CHInsertNone;
return NSDragOperationNone;
}
return NSDragOperationGeneric;
}
- (void)draggingExited:(id <NSDraggingInfo>)sender
{
if (mDragInsertionPosition)
[self setNeedsDisplayInRect:[self insertionRectForButton:mDragInsertionButton position:mDragInsertionPosition]];
mDragInsertionButton = nil;
mDragInsertionPosition = CHInsertNone;
}
- (unsigned int)draggingUpdated:(id <NSDraggingInfo>)sender
{
if (mDragInsertionPosition)
[self setNeedsDisplayInRect:[self insertionRectForButton:mDragInsertionButton position:mDragInsertionPosition]];
// we have to set the drag target before we can test for drop validation
[self setButtonInsertionPoint:sender];
if (![self dropDestinationValid:sender]) {
mDragInsertionButton = nil;
mDragInsertionPosition = CHInsertNone;
return NSDragOperationNone;
}
if (mDragInsertionPosition)
[self setNeedsDisplayInRect:[self insertionRectForButton:mDragInsertionButton position:mDragInsertionPosition]];
return NSDragOperationGeneric;
}
- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
{
return YES;
}
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
unsigned index = 0;
BookmarkFolder* toolbar = [[BookmarkManager sharedBookmarkManager] toolbarFolder];
if (!toolbar)
return NO;
if (mDragInsertionPosition == CHInsertInto) // drop onto folder
{
toolbar = (BookmarkFolder *)[mDragInsertionButton BookmarkItem];
index = 0;
}
else if (mDragInsertionPosition == CHInsertBefore ||
mDragInsertionPosition == CHInsertAfter) // drop onto toolbar
{
index = [mButtons indexOfObjectIdenticalTo: mDragInsertionButton];
if (index == NSNotFound)
index = [toolbar count];
else if (mDragInsertionPosition == CHInsertAfter)
index++;
}
else
{
mDragInsertionButton = nil;
mDragInsertionPosition = CHInsertNone;
[self setNeedsDisplay:YES];
return NO;
}
BOOL dropHandled = NO;
BOOL isCopy = ([sender draggingSourceOperationMask] == NSDragOperationCopy);
NSArray *draggedTypes = [[sender draggingPasteboard] types];
if ( [draggedTypes containsObject:@"MozBookmarkType"] )
{
NSArray *draggedItems = [NSArray pointerArrayFromDataArrayForMozBookmarkDrop:[[sender draggingPasteboard] propertyListForType: @"MozBookmarkType"]];
NSEnumerator *enumerator = [draggedItems objectEnumerator];
id aKid;
while ((aKid = [enumerator nextObject])) {
if (isCopy) {
[[aKid parent] copyChild:aKid toBookmarkFolder:toolbar atIndex:index];
} else {
[[aKid parent] moveChild:aKid toBookmarkFolder:toolbar atIndex:index];
}
}
dropHandled = YES;
}
else if ( [draggedTypes containsObject:@"MozURLType"] )
{
NSDictionary* proxy = [[sender draggingPasteboard] propertyListForType: @"MozURLType"];
[toolbar addBookmark:[proxy objectForKey:@"title"] url:[proxy objectForKey:@"url"] inPosition:index isSeparator:NO];
dropHandled = YES;
}
else if ( [draggedTypes containsObject:NSStringPboardType] )
{
NSString* draggedText = [[sender draggingPasteboard] stringForType:NSStringPboardType];
[toolbar addBookmark:draggedText url:draggedText inPosition:index isSeparator:NO];
dropHandled = YES;
}
else if ([draggedTypes containsObject: NSURLPboardType])
{
NSURL* urlData = [NSURL URLFromPasteboard:[sender draggingPasteboard]];
[toolbar addBookmark:[urlData absoluteString] url:[urlData absoluteString] inPosition:index isSeparator:NO];
dropHandled = YES;
}
mDragInsertionButton = nil;
mDragInsertionPosition = CHInsertNone;
[self setNeedsDisplay:YES];
return dropHandled;
}
- (NSRect)insertionRectForButton:(NSView*)aButton position:(int) aPosition
{
if (aPosition == CHInsertInto) {
return NSMakeRect([aButton frame].origin.x, [aButton frame].origin.y, [aButton frame].size.width, [aButton frame].size.height);
} else if (aPosition == CHInsertAfter) {
return NSMakeRect([aButton frame].origin.x+[aButton frame].size.width, [aButton frame].origin.y, 2, [aButton frame].size.height);
} else {// if (aPosition == BookmarksService::CHInsertBefore) {
return NSMakeRect([aButton frame].origin.x - 2, [aButton frame].origin.y, 2, [aButton frame].size.height);
}
}
- (BookmarkButton*)makeNewButtonWithItem:(BookmarkItem*)aItem
{
return [[[BookmarkButton alloc] initWithFrame: NSMakeRect(2, 1, 100, 17) item:aItem] autorelease];
}
#pragma mark -
- (void)bookmarkAdded:(NSNotification *)aNote
{
BookmarkFolder *anArray = [aNote object];
if (![anArray isEqual:[[BookmarkManager sharedBookmarkManager] toolbarFolder]])
return;
NSDictionary *dict = [aNote userInfo];
[self addButton:[dict objectForKey:BookmarkFolderChildKey] atIndex:[[dict objectForKey:BookmarkFolderChildIndexKey] unsignedIntValue]];
}
- (void)bookmarkRemoved:(NSNotification *)aNote
{
BookmarkFolder *aFolder = [aNote object];
if (![aFolder isEqual:[[BookmarkManager sharedBookmarkManager] toolbarFolder]])
return;
NSDictionary *dict = [aNote userInfo];
[self removeButton:[dict objectForKey:BookmarkFolderChildKey]];
}
- (void)bookmarkChanged:(NSNotification *)aNote
{
[self editButton:[aNote object]];
}
@end

Просмотреть файл

@ -0,0 +1,116 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* Combines old BookmarkController and BookmarkDataSource classes. When
* history gets brought in to new Bookmark system, HistoryDataSource will
* go away, too.
*
*
* ***** END LICENSE BLOCK ***** */
#import <Cocoa/Cocoa.h>
#import "BookmarksClient.h"
@class HistoryDataSource;
@class ExtendedTableView;
@class BrowserWindowController;
@class BookmarkOutlineView;
@class BookmarkFolder;
@interface BookmarkViewController : NSObject {
IBOutlet NSButton* mAddCollectionButton;
IBOutlet NSButton* mAddBookmarkButton;
IBOutlet NSButton* mAddFolderButton;
IBOutlet NSButton* mAddSeparatorButton;
IBOutlet NSButton* mInfoButton;
IBOutlet NSButton* mSearchButton;
IBOutlet NSTextField *mSearchField;
IBOutlet NSSplitView* mContainersSplit; // vertical split
IBOutlet NSSplitView* mItemSearchSplit; // horizontal split
IBOutlet BrowserWindowController* mBrowserWindowController;
IBOutlet ExtendedTableView* mContainerPane;
IBOutlet BookmarkOutlineView* mItemPane;
IBOutlet NSTableView* mSearchPane; // shows search results, can be hidden
IBOutlet HistoryDataSource* mHistorySource; //can swap to this for history data
NSMutableDictionary *mExpandedStatus;
NSString* mCachedHref;
BookmarkFolder *mActiveRootCollection;
BookmarkFolder *mRootBookmarks;
NSArray *mSearchResultArray;
int mOpenActionFlag;
}
//
// IBActions
//
-(IBAction) setAsDockMenuFolder:(id)aSender;
-(IBAction) addCollection:(id)aSender;
-(IBAction) addBookmark:(id)aSender;
-(IBAction) addFolder:(id)aSender;
-(IBAction) addSeparator:(id)aSender;
-(IBAction) openBookmark: (id)aSender;
-(IBAction) openBookmarkInNewTab:(id)aSender;
-(IBAction) openBookmarkInNewWindow:(id)aSender;
-(IBAction) deleteBookmarks:(id)aSender;
-(IBAction) showBookmarkInfo:(id)aSender;
-(IBAction) startSearch:(id)aSender;
-(IBAction) locateBookmark:(id)aSender;
-(void) selectContainer:(int)inRowIndex;
-(void) selectLastContainer;
-(NSMutableDictionary *)expandedStatusDictionary;
-(void) restoreFolderExpandedStates;
-(BOOL) isExpanded:(id)anItem;
-(BOOL) haveSelectedRow;
-(void) setItem:(BookmarkFolder *)anItem isExpanded:(BOOL)aBool;
-(void) setActiveCollection:(BookmarkFolder *)aFolder;
-(BookmarkFolder *)activeCollection;
-(void)addItem:(id)aSender useSelection:(BOOL)aSel isFolder:(BOOL)aIsFolder URL:(NSString*)aURL title:(NSString*)aTitle;
-(void)addItem:(id)aSender withParent:(BookmarkFolder *)parent isFolder:(BOOL)aIsFolder URL:(NSString*)aURL title:(NSString*)aTitle;
-(void)endAddBookmark: (int)aCode;
-(void)deleteCollection:(id)aSender;
-(void) focus;
-(void) windowDidLoad;
-(void) ensureBookmarks;
@end

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,63 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* David Haas <haasd@cae.wisc.edu>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import <Foundation/Foundation.h>
@protocol BookmarksClient
- (void)bookmarkAdded:(NSNotification *)note;
- (void)bookmarkRemoved:(NSNotification *)note;
- (void)bookmarkChanged:(NSNotification *)note;
@end
// Notification keys
// defined in Bookmark.h
extern NSString *URLLoadNotification; //object is NSString of URL, userinfo has NSNum of success/fail
extern NSString *URLLoadSuccessKey; //key for bool of load success/fail
// defined in BookmarkFolder.h
extern NSString* BookmarkFolderAdditionNotification; //self is obj, userinfo has added item/index
extern NSString* BookmarkFolderDeletionNotification; //self is obj, userinfo dict has removed item
extern NSString* BookmarkFolderChildKey;//key for added/removed object in userinfo dict
extern NSString* BookmarkFolderChildIndexKey; // key for added object index in userinfo dict
extern NSString* BookmarkFolderDockMenuChangeNotificaton; //self is NEW dock menu OR nil
// Defined in BookmarkItem.h
extern NSString *BookmarkItemChangedNotification; //no userinfo, self is object

Просмотреть файл

@ -0,0 +1,61 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* David Haas <haasd@cae.wisc.edu>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* By the way - this is a total hack. Somebody should really do this in
* a more intelligent manner.
*
* ***** END LICENSE BLOCK ***** */
#import <Foundation/Foundation.h>
@class BookmarkFolder;
@class BookmarkManager;
@interface KindaSmartFolderManager : NSObject {
BookmarkFolder* mBrokenBookmarkFolder;
BookmarkFolder* mUpdatedBookmarkFolder;
BookmarkFolder* mTop10Folder;
BookmarkFolder* mAddressBookFolder;
BookmarkFolder* mRendezvousFolder;
id mAddressBookManager;
unsigned mFewestVisits;
}
-(id)initWithBookmarkManager:(BookmarkManager *)manager;
-(void)postStartupInitialization:(BookmarkManager *)manager;
@end

Просмотреть файл

@ -0,0 +1,301 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* David Haas <haasd@cae.wisc.edu>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* By the way - this is a total hack. Somebody should really do this in
* a more intelligent manner.
*
* ***** END LICENSE BLOCK ***** */
#import "KindaSmartFolderManager.h"
#import "BookmarkFolder.h"
#import "Bookmark.h"
#import "BookmarkManager.h"
#import "NetworkServices.h"
#import "BookmarksClient.h"
@interface KindaSmartFolderManager (Private) <NetworkServicesClient, BookmarksClient>
-(void)addBookmark:(Bookmark *)aBookmark toSmartFolder:(BookmarkFolder *)aFolder;
-(void)removeBookmark:(Bookmark *)aBookmark fromSmartFolder:(BookmarkFolder *)aFolder;
-(void)checkForNewTop10:(Bookmark *)aBookmark;
-(void)setupAddressBook;
-(void)rebuildTop10List;
@end
@implementation KindaSmartFolderManager
-(id)initWithBookmarkManager:(BookmarkManager *)manager
{
if ((self = [super init])) {
// retain all our smart folders, just to be safe
mBrokenBookmarkFolder = [[manager brokenLinkFolder] retain];
mTop10Folder = [[manager top10Folder] retain];
mAddressBookFolder = [[manager addressBookFolder] retain];
mRendezvousFolder = [[manager rendezvousFolder] retain];
mFewestVisits = 0;
// client notifications
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:@selector(bookmarkRemoved:) name:BookmarkFolderDeletionNotification object:nil];
[nc addObserver:self selector:@selector(bookmarkChanged:) name:BookmarkItemChangedNotification object:nil];
}
return self;
}
-(void) dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[mBrokenBookmarkFolder release];
[mTop10Folder release];
[mAddressBookFolder release];
[mRendezvousFolder release];
[super dealloc];
}
-(void)postStartupInitialization:(BookmarkManager *)manager
{
// register for Rendezvous - if we need to
if (mRendezvousFolder) {
[NetworkServices sharedNetworkServices];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:@selector(availableServicesChanged:) name:NetworkServicesAvailableServicesChanged object:nil];
[nc addObserver:self selector:@selector(serviceResolved:) name:NetworkServicesResolutionSuccess object:nil];
}
if (mAddressBookFolder)
[self setupAddressBook];
// get top 10 list started
NSArray *bookmarkArray = [[manager rootBookmarks] allChildBookmarks];
unsigned i, j = [bookmarkArray count];
for (i=0; i < j; i++) {
Bookmark *aBookmark = [bookmarkArray objectAtIndex:i];
[self checkForNewTop10:aBookmark];
if ([aBookmark isSick])
[self addBookmark:aBookmark toSmartFolder:mBrokenBookmarkFolder];
}
}
// when 10.1 support is dropped, most of "init" method of AddressBookManager goes here.
// we'd also need to add that class' fillAddressBook method to this class
-(void) setupAddressBook
{
NSBundle *appBundle = [NSBundle mainBundle];
NSString *addressBookManagerBundlePath = [[appBundle resourcePath] stringByAppendingPathComponent:@"AddressBookManager.bundle"];
NSBundle *addressBookBundle = [NSBundle bundleWithPath:addressBookManagerBundlePath];
Class principalClass = [addressBookBundle principalClass];
mAddressBookManager = [[principalClass alloc] initWithFolder:mAddressBookFolder];
if (mAddressBookManager)
[mAddressBookFolder release];
}
//
// flush top 10 list & rebuild from scratch
//
-(void)rebuildTop10List
{
unsigned i, count = [mTop10Folder count];
for (i=0;i < count;i++)
[mTop10Folder deleteFromSmartFolderChildAtIndex:0];
mFewestVisits = 0;
// get top 10 list started
BookmarkManager *manager = [BookmarkManager sharedBookmarkManager];
NSArray *bookmarkArray = [[manager rootBookmarks] allChildBookmarks];
count = [bookmarkArray count];
for (i=0; i < count; i++) {
Bookmark *aBookmark = [bookmarkArray objectAtIndex:i];
[self checkForNewTop10:aBookmark];
}
}
-(void)checkForNewTop10:(Bookmark *)aBookmark
{
unsigned smallVisit = [aBookmark numberOfVisits];
if (smallVisit == 0) {
if ([mTop10Folder indexOfObjectIdenticalTo:aBookmark] != NSNotFound)
//whoops. we just cleared the visits on a top 10 item. rebuild from scratch.
[self rebuildTop10List];
return;
}
if (([mTop10Folder indexOfObjectIdenticalTo:aBookmark] != NSNotFound))
return;
// cycle through list of children
// find item with fewest visits, mark it for destruction
// if the URL from the new bookmark is already present in the
// list, we bail out
NSMutableArray *childArray = [mTop10Folder childArray];
unsigned i, kidVisit, count = [childArray count]; //j should be 10
if ((count >=10) && (smallVisit < mFewestVisits))
return;
Bookmark *aKid = nil;
NSString *newURL = [aBookmark url];
int doomedKidIndex = -1;
for (i=0; i< count; i++) {
aKid = [childArray objectAtIndex:i];
if ([newURL isEqualToString:[aKid url]])
return;
kidVisit = [aKid numberOfVisits];
if (kidVisit == mFewestVisits)
doomedKidIndex = i;
else if (smallVisit > kidVisit)
smallVisit = kidVisit;
}
if ((doomedKidIndex != -1) && (count >= 10))
[mTop10Folder deleteFromSmartFolderChildAtIndex:doomedKidIndex];
[mTop10Folder insertIntoSmartFolderChild:aBookmark];
mFewestVisits = smallVisit;
}
//
// if we don't already have it, add it
//
-(void)addBookmark:(Bookmark *)aBookmark toSmartFolder:(BookmarkFolder *)aFolder
{
unsigned index = [aFolder indexOfObjectIdenticalTo:aBookmark];
if (index == NSNotFound)
[aFolder insertIntoSmartFolderChild:aBookmark];
}
//
// if we have this item, remove it
//
-(void)removeBookmark:(Bookmark *)anItem fromSmartFolder:(BookmarkFolder *)aFolder
{
unsigned index = [aFolder indexOfObjectIdenticalTo:anItem];
if (index != NSNotFound)
[aFolder deleteFromSmartFolderChildAtIndex:index];
}
#pragma mark -
static int SortByProtocolAndName(NSDictionary* item1, NSDictionary* item2, void *context)
{
NSComparisonResult protocolCompare = [[item1 objectForKey:@"name"] compare:[item2 objectForKey:@"name"] options:NSCaseInsensitiveSearch];
if (protocolCompare != NSOrderedSame)
return protocolCompare;
return [[item1 objectForKey:@"protocol"] compare:[item2 objectForKey:@"protocol"] options:NSCaseInsensitiveSearch];
}
- (void)availableServicesChanged:(NSNotification *)note
{
// empty the rendezvous folder
unsigned i, count = [mRendezvousFolder count];
for (i=0; i < count; i++)
[mRendezvousFolder deleteChild:[mRendezvousFolder objectAtIndex:0]];
NetworkServices *netserv = [note object];
NSEnumerator* keysEnumerator = [netserv serviceEnumerator];
NSMutableArray* servicesArray = [[NSMutableArray alloc] initWithCapacity:10];
id key;
while ((key = [keysEnumerator nextObject])) {
NSDictionary* serviceDict = [NSDictionary dictionaryWithObjectsAndKeys:
key, @"id",
[netserv serviceName:[key intValue]], @"name",
[netserv serviceProtocol:[key intValue]], @"protocol",
nil];
[servicesArray addObject:serviceDict];
}
if ([servicesArray count] != 0) {
// sort on protocol, then name
[servicesArray sortUsingFunction:SortByProtocolAndName context:NULL];
unsigned count = [servicesArray count];
for (unsigned int i = 0; i < count; i ++)
{
NSDictionary* serviceDict = [servicesArray objectAtIndex:i];
NSString* itemName = [[serviceDict objectForKey:@"name"] stringByAppendingString:NSLocalizedString([serviceDict objectForKey:@"protocol"], @"")];
Bookmark *aBookmark = [mRendezvousFolder addBookmark];
[aBookmark setTitle:itemName];
[aBookmark setParent:[serviceDict objectForKey:@"id"]];
}
}
[servicesArray release];
}
- (void)serviceResolved:(NSNotification *)note
{
NSDictionary *dict = [note userInfo];
id aClient = [dict objectForKey:NetworkServicesClientKey];
if ([aClient isKindOfClass:[Bookmark class]]) {
Bookmark *aKid;
NSEnumerator* enumerator = [[mRendezvousFolder childArray] objectEnumerator];
while ((aKid = [enumerator nextObject])) {
if (aKid == aClient)
{
[aClient setUrl:[dict objectForKey:NetworkServicesResolvedURLKey]];
[aClient setParent:mRendezvousFolder];
}
}
}
return;
}
- (void)serviceResolutionFailed:(NSNotification *)note
{
return;
}
#pragma mark -
//
// BookmarkClient protocol
//
- (void)bookmarkAdded:(NSNotification *)note
{
}
//
// need to tell top 10 list, broken items
//
- (void)bookmarkRemoved:(NSNotification *)note
{
BookmarkItem *anItem = [[note userInfo] objectForKey:BookmarkFolderChildKey];
if (![anItem parent] && [anItem isKindOfClass:[Bookmark class]]) {
[self removeBookmark:anItem fromSmartFolder:mBrokenBookmarkFolder];
[self removeBookmark:anItem fromSmartFolder:mTop10Folder];
}
}
- (void)bookmarkChanged:(NSNotification *)note
{
BookmarkItem *anItem = [note object];
if ([anItem isKindOfClass:[Bookmark class]]) {
[self checkForNewTop10:anItem];
// see what the status is
if ([(Bookmark *)anItem isSick])
[self addBookmark:anItem toSmartFolder:mBrokenBookmarkFolder];
else {
[self removeBookmark:anItem fromSmartFolder:mBrokenBookmarkFolder];
}
}
}
@end

Просмотреть файл

@ -28,7 +28,7 @@
#include "nsIAutoCompleteResults.h"
#include "nsIAutoCompleteListener.h"
@class BookmarksOutlineView, PageProxyIcon;
@class PageProxyIcon;
@interface AutoCompleteTextField : NSTextField
{

Просмотреть файл

@ -509,7 +509,7 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener)
if (url) {
[self clearResults];
NSTextView *fieldEditor = [self fieldEditor];
[[fieldEditor undoManager] removeAllActions];
[[fieldEditor undoManager] removeAllActionsWithTarget:self];
[fieldEditor setString:url];
[fieldEditor selectAll:self];
}
@ -679,7 +679,8 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener)
- (void)controlTextDidEndEditing:(NSNotification *)aNote
{
[self clearResults];
[[[[aNote userInfo] objectForKey:@"NSFieldEditor"] undoManager] removeAllActions];
id fieldEditor = [[aNote userInfo] objectForKey:@"NSFieldEditor"];
[[fieldEditor undoManager] removeAllActionsWithTarget:fieldEditor];
}
- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command

Просмотреть файл

@ -38,12 +38,12 @@
#import <Cocoa/Cocoa.h>
@class BookmarksToolbar;
@class BookmarkToolbar;
@class BrowserTabView;
@interface BrowserContentView : NSView
{
IBOutlet BookmarksToolbar *mBookmarksToolbar;
IBOutlet BookmarkToolbar *mBookmarksToolbar;
IBOutlet NSView *mBrowserContainerView; // manages tabs and web content
IBOutlet NSView *mBookmarkManagerView; // swapped in and out by activating bm manager, replacing browser container
IBOutlet NSView *mStatusBar;

Просмотреть файл

@ -38,7 +38,7 @@
#import "BrowserContentViews.h"
#import "BookmarksToolbar.h"
#import "BookmarkToolbar.h"
#import "BrowserTabView.h"
@ -65,7 +65,7 @@
| _________________________________________________________________
| BrowserContentView |
| ____________________________________________________________ |
| | BookmarksToolbar | |
| | BookmarkToolbar | |
| |___________________________________________________________| |
| |
| ____________________________________________________________ |

Просмотреть файл

@ -39,11 +39,14 @@
#import "NSString+Utils.h"
#import "NSPasteboard+Utils.h"
#import "NSArray+Utils.h"
#import "BrowserTabView.h"
#import "BookmarksService.h"
#import "BrowserWrapper.h"
#import "BrowserWindowController.h"
#import "BookmarkFolder.h"
#import "Bookmark.h"
#import "BookmarkToolbar.h"
//////////////////////////
// NEEDS IMPLEMENTED : Implement drag tracking for moving tabs around.
@ -228,7 +231,7 @@
if (tabVisibilityChanged)
{
[[[[self window] windowController] bookmarksToolbar] setDrawBottomBorder:!tabsVisible];
[[[[self window] windowController] bookmarkToolbar] setDrawBottomBorder:!tabsVisible];
// tell the superview to resize its subviews
[[self superview] resizeSubviewsWithOldSize:[[self superview] frame].size];
@ -363,27 +366,30 @@ const float kTabsInvisibleTopGap = -7.0; // space removed to push tab content
if ([pasteBoardTypes containsObject: @"MozBookmarkType"])
{
NSArray* contentIds = [[sender draggingPasteboard] propertyListForType: @"MozBookmarkType"];
if (contentIds)
NSArray* draggedItems = [NSArray pointerArrayFromDataArrayForMozBookmarkDrop:[[sender draggingPasteboard] propertyListForType: @"MozBookmarkType"]];
if (draggedItems)
{
BookmarksManager* bmManager = [BookmarksManager sharedBookmarksManager];
// drag type is chimera bookmarks
for (unsigned int i = 0; i < [contentIds count]; ++i)
{
BookmarkItem* item = [bmManager getWrapperForNumber:[contentIds objectAtIndex:i]];
if ([item isGroup])
{
NSArray* groupURLs = [bmManager getBookmarkGroupURIs:item];
[[[self window] windowController] openTabGroup:groupURLs replaceExistingTabs:YES];
id aBookmark;
if ([draggedItems count] == 1) {
aBookmark = [draggedItems objectAtIndex:0];
if ([aBookmark isKindOfClass:[Bookmark class]])
return [self handleDropOnTab:overTabViewItem overContent:overContentArea withURL:[aBookmark url]];
else if ([aBookmark isKindOfClass:[BookmarkFolder class]]) {
[[[self window] windowController] openTabGroup:[aBookmark childURLs] replaceExistingTabs:YES];
return YES;
}
else
{
// handle multiple items?
return [self handleDropOnTab:overTabViewItem overContent:overContentArea withURL:[item url]];
} else if ([draggedItems count] > 1) {
NSMutableArray *urlArray = [NSMutableArray arrayWithCapacity:[draggedItems count]];
NSEnumerator *enumerator = [draggedItems objectEnumerator];
while ((aBookmark = [enumerator nextObject])) {
if ([aBookmark isKindOfClass:[Bookmark class]])
[urlArray addObject:[aBookmark url]];
else if ([aBookmark isKindOfClass:[BookmarkFolder class]])
[urlArray addObjectsFromArray:[aBookmark childURLs]];
}
} // for each item
[[[self window] windowController] openTabGroup:urlArray replaceExistingTabs:YES];
return YES;
}
}
}
else if ([pasteBoardTypes containsObject: @"MozURLType"])

Просмотреть файл

@ -293,7 +293,7 @@
NSWindowController *windowController = [[[mTabViewItem view] window] windowController];
if ([windowController isMemberOfClass:[BrowserWindowController class]])
{
if (sender == [windowController proxyIconView])
if (sender == [(BrowserWindowController *)windowController proxyIconView])
return NO;
}
@ -421,7 +421,7 @@
{
// set the tag of every menu item to the tab view item's tag,
// so that the target of the menu commands know which one they apply to.
for (unsigned int i = 0; i < [aMenu numberOfItems]; i ++)
for (int i = 0; i < [aMenu numberOfItems]; i ++)
[[aMenu itemAtIndex:i] setTag:[mTabViewItem tag]];
[super setMenu:aMenu];

Просмотреть файл

@ -38,14 +38,12 @@
#import <Cocoa/Cocoa.h>
#import "BrowserWrapper.h"
#import "Find.h"
#import "BookmarksToolbar.h"
class nsIURIFixup;
class nsIBrowserHistory;
class nsIDOMEvent;
class nsIDOMNode;
@class BookmarksController;
//
// ThrobberHandler
@ -87,7 +85,8 @@ typedef enum
} ENewTabContents;
@class BookmarksDataSource;
@class BookmarkViewController;
@class BookmarkToolbar;
@class HistoryDataSource;
@class BrowserTabView;
@class PageProxyIcon;
@ -99,9 +98,6 @@ typedef enum
@interface BrowserWindowController : NSWindowController<Find>
{
IBOutlet BrowserTabView* mTabBrowser;
IBOutlet NSDrawer* mSidebarDrawer;
IBOutlet NSTabView* mSidebarTabView;
IBOutlet NSTabView* mSidebarSourceTabView;
IBOutlet NSView* mLocationToolbarView;
IBOutlet AutoCompleteTextField* mURLBar;
IBOutlet NSTextField* mStatus;
@ -114,12 +110,9 @@ typedef enum
IBOutlet PageProxyIcon* mProxyIcon;
IBOutlet BrowserContentView* mContentView;
IBOutlet BookmarksDataSource* mSidebarBookmarksDataSource;
IBOutlet BookmarkViewController* mBookmarkViewController;
IBOutlet BookmarkToolbar* mPersonalToolbar;
IBOutlet HistoryDataSource* mHistoryDataSource;
IBOutlet BookmarksController* mBookmarksController;
IBOutlet BookmarksToolbar* mPersonalToolbar;
IBOutlet NSWindow* mAddBookmarkSheetWindow;
IBOutlet NSTextField* mAddBookmarkTitleField;
IBOutlet NSPopUpButton* mAddBookmarkFolderField;
@ -158,10 +151,6 @@ typedef enum
BOOL mShouldAutosave;
BOOL mShouldLoadHomePage;
BOOL mDrawerCachedFrame;
NSRect mCachedFrameBeforeDrawerOpen; // This is used by the drawer to figure out if the window should
// be returned to its original position when the drawer closes.
NSRect mCachedFrameAfterDrawerOpen;
unsigned int mChromeMask; // Indicates which parts of the window to show (e.g., don't show toolbars)
@ -171,7 +160,7 @@ typedef enum
nsIDOMNode* mContextMenuNode;
// Cached bookmark ds used when adding through a sheet
BookmarksDataSource* mCachedBMDS;
BookmarkViewController* mCachedBMVC;
// Throbber state variables.
ThrobberHandler* mThrobberHandler;
@ -229,7 +218,7 @@ typedef enum
- (IBAction)cancelAddBookmarkSheet:(id)sender;
- (IBAction)endAddBookmarkSheet:(id)sender;
- (void)cacheBookmarkDS:(BookmarksDataSource*)aDS;
- (void)cacheBookmarkVC:(BookmarkViewController *)aDS;
- (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)proposedFrameSize;
@ -259,7 +248,6 @@ typedef enum
- (void)addBookmarkExtended: (BOOL)aIsFromMenu isFolder:(BOOL)aIsFolder URL:(NSString*)aURL title:(NSString*)aTitle;
- (IBAction)manageBookmarks: (id)aSender;
- (IBAction)manageHistory: (id)aSender;
- (void)importBookmarks: (NSString*)aURLSpec;
- (IBAction)toggleSidebar:(id)aSender;
- (BOOL)bookmarksAreVisible:(BOOL)inRequireSelection;
@ -290,7 +278,7 @@ typedef enum
- (IBAction)frameToThisWindow:(id)sender;
- (void)openNewWindowWithURL: (NSString*)aURLSpec referrer:(NSString*)aReferrer loadInBackground: (BOOL)aLoadInBG;
- (void)openNewWindowWithGroup: (nsIContent*)aFolderContent loadInBackground: (BOOL)aLoadInBG;
- (void)openNewWindowWithGroupURLs: (NSArray *)urlArray loadInBackground: (BOOL)aLoadInBG;
- (void)openNewTabWithURL: (NSString*)aURLSpec referrer: (NSString*)aReferrer loadInBackground: (BOOL)aLoadInBG;
- (void)openTabGroup:(NSArray*)urlArray replaceExistingTabs:(BOOL)replaceExisting;
@ -334,7 +322,7 @@ typedef enum
- (IBAction)copyImage:(id)sender;
- (IBAction)copyImageLocation:(id)sender;
- (BookmarksToolbar*) bookmarksToolbar;
- (BookmarkToolbar*) bookmarkToolbar;
- (NSProgressIndicator*) progressIndicator;
- (void) showProgressIndicator;
@ -357,14 +345,11 @@ typedef enum
// cache the toolbar defaults we parse from a plist
+ (NSArray*) toolbarDefaults;
// Accessor to get the sidebar drawer
- (NSDrawer *)sidebarDrawer;
// Accessor to get the proxy icon view
- (PageProxyIcon *)proxyIconView;
// Accessor for the bm data source
- (BookmarksDataSource*)bookmarksDataSource;
- (BookmarkViewController *)bookmarkViewController;
- (void)toggleBookmarkManager:(id)sender;
- (void)ensureBrowserVisible:(id)sender;

Просмотреть файл

@ -40,19 +40,22 @@
#import "BrowserWindowController.h"
#import "BrowserWindow.h"
#import "BookmarkToolbar.h"
#import "BookmarkViewController.h"
#import "BookmarkManager.h"
#import "BrowserContentViews.h"
#import "BrowserWrapper.h"
#import "PreferenceManager.h"
#import "BookmarksDataSource.h"
#import "HistoryDataSource.h"
#import "BrowserTabView.h"
#import "UserDefaults.h"
#import "PageProxyIcon.h"
#import "AutoCompleteTextField.h"
#import "BookmarksController.h"
#import "SearchTextField.h"
#import "SearchTextFieldCell.h"
#import "STFPopUpButtonCell.h"
#import "MainController.h"
#include "nsIWebNavigation.h"
#include "nsIDOMDocument.h"
@ -121,6 +124,7 @@ static NSArray* sToolbarDefaults = nil;
@interface AutoCompleteTextFieldEditor : NSTextView
{
NSFont* mDefaultFont; // will be needed if editing empty field
NSUndoManager *mUndoManager; //we handle our own undo to avoid stomping on bookmark undo
}
- (id)initWithFrame:(NSRect)bounds defaultFont:(NSFont*)defaultFont;
@end
@ -132,10 +136,18 @@ static NSArray* sToolbarDefaults = nil;
{
if ((self = [super initWithFrame:bounds])) {
mDefaultFont = defaultFont;
mUndoManager = [[NSUndoManager alloc] init];
[self setDelegate:self];
}
return self;
}
-(void) dealloc
{
[mUndoManager release];
[super dealloc];
}
-(void)paste:(id)sender
{
NSPasteboard *pboard = [NSPasteboard generalPasteboard];
@ -160,6 +172,13 @@ static NSArray* sToolbarDefaults = nil;
}
}
- (NSUndoManager *)undoManagerForTextView:(NSTextView *)aTextView
{
if (aTextView == self)
return mUndoManager;
return nil;
}
@end
//////////////////////////////////////
@ -344,8 +363,6 @@ static NSArray* sToolbarDefaults = nil;
#if DEBUG
NSLog(@"Window will close notification.");
#endif
[mSidebarBookmarksDataSource windowClosing];
[self autosaveWindowFrame];
{ // scope...
@ -511,8 +528,6 @@ static NSArray* sToolbarDefaults = nil;
mustResizeChrome = YES;
mInitialized = YES;
mDrawerCachedFrame = NO;
[[self window] setAcceptsMouseMovedEvents: YES];
@ -542,11 +557,6 @@ static NSArray* sToolbarDefaults = nil;
mPendingURL = mPendingReferrer = nil;
}
#if USE_DRAWER_FOR_BOOKMARKS
[mSidebarDrawer setDelegate: self];
[self setupSidebarTabs];
#endif
if ( mChromeMask && !(mChromeMask & nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR) ) {
// remove the personal toolbar and adjust the content area upwards. Removing it
// from the parent view releases it, so we have to clear out the member var.
@ -557,7 +567,7 @@ static NSArray* sToolbarDefaults = nil;
}
else
{
[mPersonalToolbar initializeToolbar];
[mPersonalToolbar buildButtonList];
if (![self shouldShowBookmarkToolbar])
[mPersonalToolbar showBookmarksToolbar:NO];
@ -590,7 +600,7 @@ static NSArray* sToolbarDefaults = nil;
}
// let the in-window bookmark controller finish up some initialization
[mBookmarksController windowDidLoad];
[mBookmarkViewController windowDidLoad];
}
- (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)proposedFrameSize
@ -604,7 +614,7 @@ static NSArray* sToolbarDefaults = nil;
#if 0
- (void)drawerWillOpen: (NSNotification*)aNotification
{
[mSidebarBookmarksDataSource ensureBookmarks];
[mBookmarkViewController ensureBookmarks];
if ([[[mSidebarTabView selectedTabViewItem] identifier] isEqual:@"historySidebarCHIconTabViewItem"]) {
[mHistoryDataSource ensureDataSourceLoaded];
@ -1100,19 +1110,19 @@ static NSArray* sToolbarDefaults = nil;
{
[mAddBookmarkSheetWindow orderOut:self];
[NSApp endSheet:mAddBookmarkSheetWindow returnCode:0];
[mCachedBMDS endAddBookmark: 0];
[mCachedBMVC endAddBookmark: 0];
}
-(IBAction)endAddBookmarkSheet:(id)sender
{
[mAddBookmarkSheetWindow orderOut:self];
[NSApp endSheet:mAddBookmarkSheetWindow returnCode:0];
[mCachedBMDS endAddBookmark: 1];
[mCachedBMVC endAddBookmark: 1];
}
- (void)cacheBookmarkDS:(BookmarksDataSource*)aDS
- (void)cacheBookmarkVC:(BookmarkViewController *)aVC
{
mCachedBMDS = aDS;
mCachedBMVC = aVC;
}
-(IBAction)manageBookmarks: (id)aSender
@ -1120,7 +1130,7 @@ static NSArray* sToolbarDefaults = nil;
if ( ![mContentView isBookmarkManagerVisible] )
[self toggleBookmarkManager: self];
[mBookmarksController selectContainer:kBookmarksMenuContainer];
[mBookmarkViewController selectContainer:kBookmarkMenuContainerIndex];
}
-(IBAction)manageHistory: (id)aSender
@ -1128,20 +1138,7 @@ static NSArray* sToolbarDefaults = nil;
if ( ![mContentView isBookmarkManagerVisible] )
[self toggleBookmarkManager: self];
[mBookmarksController selectContainer:kHistoryContainer];
}
- (void)importBookmarks: (NSString*)aURLSpec
{
// Open the bookmarks sidebar.
[self manageBookmarks: self];
// Now do the importing.
BrowserWrapper* newView = [[[BrowserWrapper alloc] initWithTab: nil andWindow: [self window]] autorelease];
[newView setFrame: NSZeroRect];
[newView setIsBookmarksImport: YES];
[[[self window] contentView] addSubview: newView];
[newView loadURI:aURLSpec referrer: nil flags:NSLoadFlagsNone activate:NO];
[mBookmarkViewController selectContainer:kHistoryContainerIndex];
}
- (IBAction)goToLocationFromToolbarURLField:(id)sender
@ -1150,7 +1147,7 @@ static NSArray* sToolbarDefaults = nil;
NSString *theURL = [[sender stringValue] stringByTrimmingWhitespace];
// look for bookmarks keywords match
NSArray *resolvedURLs = [[BookmarksManager sharedBookmarksManager] resolveBookmarksKeyword:theURL];
NSArray *resolvedURLs = [[BookmarkManager sharedBookmarkManager] resolveBookmarksKeyword:theURL];
NSString* resolvedURL = nil;
if ([resolvedURLs count] == 1)
@ -1466,14 +1463,13 @@ static NSArray* sToolbarDefaults = nil;
- (void)addBookmarkExtended: (BOOL)aIsFromMenu isFolder:(BOOL)aIsFolder URL:(NSString*)aURL title:(NSString*)aTitle
{
[mSidebarBookmarksDataSource ensureBookmarks];
[mBookmarkViewController ensureBookmarks];
BOOL useSel = aIsFromMenu;
if (aIsFromMenu) {
// Use selection only if the sidebar is open and the bookmarks panel is displaying.
useSel = [self bookmarksAreVisible:NO];
}
[mSidebarBookmarksDataSource addBookmark: self useSelection: useSel isFolder: aIsFolder URL:aURL title:aTitle];
[mBookmarkViewController addItem: self useSelection: useSel isFolder: aIsFolder URL:aURL title:aTitle];
}
- (BOOL)bookmarksAreVisible:(BOOL)inRequireSelection
@ -1481,7 +1477,7 @@ static NSArray* sToolbarDefaults = nil;
BOOL bookmarksShowing = [mContentView isBookmarkManagerVisible];
if (inRequireSelection)
bookmarksShowing &= ([mSidebarBookmarksDataSource haveSelectedRow]);
bookmarksShowing &= ([mBookmarkViewController haveSelectedRow]);
return bookmarksShowing;
}
@ -1849,21 +1845,6 @@ static NSArray* sToolbarDefaults = nil;
}
}
- (void)tabView:(NSTabView *)tabView willSelectTabViewItem:(NSTabViewItem *)tabViewItem
{
// we'll get called for browser tab views as well. ignore any calls coming from
// there, we're only interested in the sidebar.
if (tabView != mSidebarTabView)
return;
if ([[tabViewItem identifier] isEqual:@"historySidebarCHIconTabViewItem"]) {
[mHistoryDataSource ensureDataSourceLoaded];
[mHistoryDataSource enableObserver];
}
else
[mHistoryDataSource disableObserver];
}
- (void)tabView:(NSTabView *)aTabView didSelectTabViewItem:(NSTabViewItem *)aTabViewItem
{
// we'll get called for the sidebar tabs as well. ignore any calls coming from
@ -1922,7 +1903,7 @@ static NSArray* sToolbarDefaults = nil;
[browser showWindow:self];
}
- (void)openNewWindowWithGroup: (nsIContent*)aFolderContent loadInBackground: (BOOL)aLoadInBG
- (void)openNewWindowWithGroupURLs: (NSArray *)urlArray loadInBackground: (BOOL)aLoadInBG
{
// Autosave our dimensions before we open a new window. That ensures the size ends up matching.
[self autosaveWindowFrame];
@ -1938,12 +1919,7 @@ static NSArray* sToolbarDefaults = nil;
}
else
[browser showWindow:self];
BookmarksManager* bmManager = [BookmarksManager sharedBookmarksManager];
BookmarkItem* item = [bmManager getWrapperForContent:aFolderContent];
NSArray* groupURLs = [bmManager getBookmarkGroupURIs:item];
[browser openTabGroup:groupURLs replaceExistingTabs:YES];
[browser openTabGroup:urlArray replaceExistingTabs:YES];
}
-(void)openNewTabWithURL: (NSString*)aURLSpec referrer:(NSString*)aReferrer loadInBackground: (BOOL)aLoadInBG
@ -2103,8 +2079,8 @@ static NSArray* sToolbarDefaults = nil;
- (void)getInfo:(id)sender
{
[mSidebarBookmarksDataSource ensureBookmarks];
[mSidebarBookmarksDataSource showBookmarkInfo:sender];
[mBookmarkViewController ensureBookmarks];
[mBookmarkViewController showBookmarkInfo:sender];
}
- (BOOL)canGetInfo
@ -2343,7 +2319,7 @@ static NSArray* sToolbarDefaults = nil;
}
}
- (BookmarksToolbar*) bookmarksToolbar
- (BookmarkToolbar*) bookmarkToolbar
{
return mPersonalToolbar;
}
@ -2553,19 +2529,15 @@ static NSArray* sToolbarDefaults = nil;
[[mBrowserView getBrowserView] setActive:newResponderIsGecko];
}
- (NSDrawer *)sidebarDrawer
{
return mSidebarDrawer;
}
- (PageProxyIcon *)proxyIconView
{
return mProxyIcon;
}
- (BookmarksDataSource*)bookmarksDataSource
- (BookmarkViewController *)bookmarkViewController
{
return mSidebarBookmarksDataSource;
return mBookmarkViewController;
}
- (id)windowWillReturnFieldEditor:(NSWindow *)aWindow toObject:(id)anObject
@ -2582,6 +2554,10 @@ static NSArray* sToolbarDefaults = nil;
return nil;
}
- (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)sender
{
return [[BookmarkManager sharedBookmarkManager] undoManager];
}
- (IBAction)reloadWithNewCharset:(NSString*)charset
{
@ -2618,10 +2594,10 @@ static NSArray* sToolbarDefaults = nil;
// cancel all pending loads. safari does this, i think we should too
[self stopAllPendingLoads];
[mBookmarksController selectLastContainer];
[mBookmarkViewController selectLastContainer];
// set focus to appropriate area of bm manager
[mBookmarksController focus];
[mBookmarkViewController focus];
}
else {
CHBrowserView* browserView = [mBrowserView getBrowserView];

Просмотреть файл

@ -80,8 +80,6 @@ class nsISupportsArray;
BOOL mOffline;
BOOL mListenersAttached; // We hook up our click and context menu listeners lazily.
// If we never become the primary view, we don't bother creating the listeners.
BOOL mIsBookmarksImport; // This view was created for the purpose of importing bookmarks. Upon
// completion, we need to do the import and then destroy ourselves.
BOOL mActivateOnLoad; // If set, activate the browser view when loading starts.
}
@ -111,8 +109,6 @@ class nsISupportsArray;
- (NSWindow*)getNativeWindow;
- (NSMenu*)getContextMenu;
- (void)setIsBookmarksImport:(BOOL)aIsImport;
- (void)getTitle:(NSString **)outTitle andHref:(NSString**)outHrefString;
// CHBrowserListener messages

Просмотреть файл

@ -40,7 +40,7 @@
#import "PreferenceManager.h"
#import "BrowserWrapper.h"
#import "BrowserWindowController.h"
#import "BookmarksService.h"
#import "BookmarksClient.h"
#import "SiteIconProvider.h"
#import "BrowserTabViewItem.h"
#import "ToolTip.h"
@ -92,7 +92,6 @@ const NSString* kOfflineNotificationName = @"offlineModeChanged";
{
mTabItem = aTab;
mWindow = aWindow;
mIsBookmarksImport = NO;
return [self initWithFrame: NSZeroRect];
}
@ -388,26 +387,17 @@ const NSString* kOfflineNotificationName = @"offlineModeChanged";
mProgress = 1.0;
mIsBusy = NO;
// need to check succeeded here because for a charset-induced reload,
// this can get called initially with a failure code.
if (mIsBookmarksImport && succeeded)
{
nsCOMPtr<nsIDOMWindow> domWindow;
nsCOMPtr<nsIWebBrowser> webBrowser = getter_AddRefs([mBrowserView getWebBrowser]);
webBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
if (domWindow)
{
nsCOMPtr<nsIDOMDocument> domDocument;
domWindow->GetDocument(getter_AddRefs(domDocument));
if (domDocument)
BookmarksService::ImportBookmarks(domDocument);
}
[self windowClosed];
[self removeFromSuperview];
}
if (mWindowController)
[mWindowController loadingDone];
// send a little love to the bookmarks
NSString *urlString = nil;
NSString *titleString = nil;
[self getTitle:&titleString andHref:&urlString];
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedInt:0] forKey:URLLoadSuccessKey];
if (urlString && ![urlString isEqualToString:@"about:blank"]) {
NSNotification *note = [NSNotification notificationWithName:URLLoadNotification object:urlString userInfo:userInfo];
[[NSNotificationQueue defaultQueue] enqueueNotification:note postingStyle:NSPostWhenIdle];
}
}
- (void)onProgressChange:(int)currentBytes outOf:(int)maxBytes
@ -438,7 +428,7 @@ const NSString* kOfflineNotificationName = @"offlineModeChanged";
// if the favicon uri has changed, fire off favicon load. When it completes, our
// imageLoadedNotification selector gets called.
if (![faviconURI isEqualToString:mSiteIconURI])
siteIconLoadInitiated = [faviconProvider loadFavoriteIcon:self forURI:urlSpec withUserData:nil allowNetwork:YES];
siteIconLoadInitiated = [faviconProvider loadFavoriteIcon:self forURI:urlSpec allowNetwork:YES];
}
else
{
@ -675,11 +665,6 @@ const NSString* kOfflineNotificationName = @"offlineModeChanged";
*outTitle = [NSString stringWithString:*outHrefString];
}
-(void)setIsBookmarksImport:(BOOL)aIsImport
{
mIsBookmarksImport = aIsImport;
}
- (void)offlineModeChanged: (NSNotification*)aNotification
{
nsCOMPtr<nsIIOService> ioService(do_GetService(ioServiceContractID));
@ -827,10 +812,6 @@ const NSString* kOfflineNotificationName = @"offlineModeChanged";
if (resetTabIcon || ![tabItem tabIcon])
[tabItem setTabIcon:mSiteIconImage isDraggable:tabIconDraggable];
}
// make sure any bookmark items that use this favicon uri are updated
if (inSiteIcon)
[[BookmarksManager sharedBookmarksManager] updateProxyImage:inSiteIcon forSiteIcon:inSiteIconURI];
}
- (void)registerNotificationListener

Просмотреть файл

@ -23,10 +23,9 @@
#import "NSString+Utils.h"
#import "NSPasteboard+Utils.h"
#import "BrowserWindowController.h"
#import "PageProxyIcon.h"
#import "BookmarksService.h"
#import "MainController.h"
#include "nsCRT.h"

Просмотреть файл

@ -49,6 +49,7 @@ class NeckoCacheHelper;
@interface SiteIconProvider : NSObject<RemoteLoadListener>
{
NeckoCacheHelper* mMissedIconsCacheHelper;
NSMutableDictionary *mRequestDict;
}
+ (SiteIconProvider*)sharedFavoriteIconProvider;
@ -64,7 +65,7 @@ class NeckoCacheHelper;
// This method returns YES if the uri request was dispatched (i.e. if we know
// that we've looked for, and failed to find, this icon before). If it returns
// YES, then the 'SiteIconLoadNotificationName' notification will be sent out.
// userData is not retained.
- (BOOL)loadFavoriteIcon:(id)sender forURI:(NSString *)inURI withUserData:(id)userData allowNetwork:(BOOL)inAllowNetwork;
- (BOOL)loadFavoriteIcon:(id)sender forURI:(NSString *)inURI allowNetwork:(BOOL)inAllowNetwork;
@end

Просмотреть файл

@ -211,6 +211,7 @@ static nsresult MakeFaviconURIFromURI(const nsAString& inURIString, nsAString& o
if ((self = [super init]))
{
mMissedIconsCacheHelper = new NeckoCacheHelper("Favicon", "Missed");
mRequestDict = [[NSMutableDictionary alloc] initWithCapacity:5];
nsresult rv = mMissedIconsCacheHelper->Init("MissedIconsCache");
if (NS_FAILED(rv)) {
delete mMissedIconsCacheHelper;
@ -224,6 +225,7 @@ static nsresult MakeFaviconURIFromURI(const nsAString& inURIString, nsAString& o
- (void)dealloc
{
delete mMissedIconsCacheHelper;
[mRequestDict release];
[super dealloc];
}
@ -246,7 +248,7 @@ static nsresult MakeFaviconURIFromURI(const nsAString& inURIString, nsAString& o
return inCache;
}
- (BOOL)loadFavoriteIcon:(id)sender forURI:(NSString *)inURI withUserData:(id)userData allowNetwork:(BOOL)inAllowNetwork
- (BOOL)loadFavoriteIcon:(id)sender forURI:(NSString *)inURI allowNetwork:(BOOL)inAllowNetwork
{
// look for a favicon
nsAutoString uriString;
@ -264,9 +266,10 @@ static nsresult MakeFaviconURIFromURI(const nsAString& inURIString, nsAString& o
{
return NO;
}
// preserve requesting URI for later notification
[mRequestDict setObject:inURI forKey:faviconString];
RemoteDataProvider* dataProvider = [RemoteDataProvider sharedRemoteDataProvider];
return [dataProvider loadURI:faviconString forTarget:sender withListener:self withUserData:userData allowNetworking:inAllowNetwork];
return [dataProvider loadURI:faviconString forTarget:sender withListener:self withUserData:nil allowNetworking:inAllowNetwork];
}
#define SITE_ICON_EXPIRATION_SECONDS (60 * 60 * 24 * 7) // 1 week
@ -304,17 +307,23 @@ static nsresult MakeFaviconURIFromURI(const nsAString& inURIString, nsAString& o
[faviconImage setScalesWhenResized:YES];
[faviconImage setSize:NSMakeSize(16, 16)];
}
// figure out what URL triggered this favicon request
NSString *requestURL = [mRequestDict objectForKey:inURI];
if (!requestURL)
requestURL = [NSString string];
// we always send out the notification, so that clients know
// about failed requests
NSDictionary* notificationData = [NSDictionary dictionaryWithObjectsAndKeys:
inURI, SiteIconLoadURIKey,
faviconImage, SiteIconLoadImageKey, // may be nil
userData, SiteIconLoadUserDataKey,
requestURL, SiteIconLoadUserDataKey,
nil];
[[NSNotificationCenter defaultCenter] postNotificationName: SiteIconLoadNotificationName
object:target userInfo:notificationData];
NSNotification *note = [NSNotification notificationWithName: SiteIconLoadNotificationName object:target userInfo:notificationData];
[[NSNotificationQueue defaultQueue] enqueueNotification: note postingStyle:NSPostWhenIdle];
// cleanup our key holder
[mRequestDict removeObjectForKey:inURI];
}
#pragma mark -

Просмотреть файл

@ -45,15 +45,16 @@
#include "nsIURI.h"
#include "nsIDOMWindow.h"
//#include "nsIWidget.h"
// XPCOM and String includes
#include "nsIRequest.h"
#include "nsCRT.h"
#include "nsString.h"
#include "nsCOMPtr.h"
#include "nsIDOMPopupBlockedEvent.h"
#include "nsNetError.h"
#import "CHBrowserView.h"
#import "BookmarksClient.h"
#import "Bookmark.h"
#include "CHBrowserListener.h"
@ -529,15 +530,36 @@ CHBrowserListener::OnStateChange(nsIWebProgress *aWebProgress, nsIRequest *aRequ
{
NSEnumerator* enumerator = [mListeners objectEnumerator];
id<CHBrowserListener> obj;
if (aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK) {
if (aStateFlags & nsIWebProgressListener::STATE_START) {
while ((obj = [enumerator nextObject]))
[obj onLoadingStarted];
}
else if (aStateFlags & nsIWebProgressListener::STATE_STOP) {
while ((obj = [enumerator nextObject]))
// we need to pass along errors like this so our bookmarks know
// if they're still OK
NSNumber *errNum = nil;
if ((aStatus == NS_ERROR_UNKNOWN_HOST ||
aStatus == NS_ERROR_CONNECTION_REFUSED ||
aStatus == NS_ERROR_UNKNOWN_PROXY_HOST ||
aStatus == NS_ERROR_PROXY_CONNECTION_REFUSED))
errNum = [NSNumber numberWithUnsignedInt:kBookmarkServerErrorStatus];
else if (( aStatus == NS_ERROR_MALFORMED_URI ||
aStatus == NS_ERROR_UNKNOWN_PROTOCOL))
errNum = [NSNumber numberWithUnsignedInt:kBookmarkBrokenLinkStatus];
else if ((aStatus == NS_BINDING_REDIRECTED))
errNum = [NSNumber numberWithUnsignedInt:kBookmarkMovedLinkStatus];
if (errNum) {
nsCAutoString uriString;
aRequest->GetName(uriString);
NSString *fixedURL = [NSString stringWithCString:uriString.get()];
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:errNum forKey:URLLoadSuccessKey];
NSNotification *note = [NSNotification notificationWithName:URLLoadNotification object:fixedURL userInfo:userInfo];
[[NSNotificationQueue defaultQueue] enqueueNotification:note postingStyle:NSPostWhenIdle];
}
while ((obj = [enumerator nextObject])) {
[obj onLoadingCompleted:(NS_SUCCEEDED(aStatus))];
}
}
}

Просмотреть файл

@ -1,26 +1,42 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the 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/
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
* 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 the Mozilla browser.
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2002 Netscape Communications Corporation. All
* Rights Reserved.
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* David Hyatt <hyatt@netscape.com> (Original Author)
* Max Horn <max@quendi.de> (Context menu & tooltip code)
*/
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import <AppKit/AppKit.h>
@ -43,7 +59,8 @@
-(void)setDeleteAction: (SEL)deleteAction;
-(SEL)deleteAction;
-(void)setDelegate:(id)anObject;
-(void)_editItem:(id)item;
-(void)_cancelEditItem;
@end

Просмотреть файл

@ -1,26 +1,42 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the 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/
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
* 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 the Mozilla browser.
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2002 Netscape Communications Corporation. All
* Rights Reserved.
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* David Hyatt <hyatt@netscape.com> (Original Author)
* Max Horn <max@quendi.de> (Context menu, tooltip code, and editing)
*/
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import "ExtendedOutlineView.h"
@ -186,7 +202,9 @@
if ([delegate respondsToSelector:@selector(outlineView:contextMenuForItem:)])
return [delegate outlineView:self contextMenuForItem:item];
}
} else
// no item, no context menu
return nil;
}
// Just return the default context menu
@ -283,7 +301,7 @@
// Little trick: if editing was already in progress, then the field editor
// will be first responder. For our purposes this is the same as if we
// were first responder, so pretend it were so.
if (oldEditRow >= 0)
if (oldEditRow > -1)
wasFirstResponder = YES;
// If we already were first responder of the main window, and the click was

Просмотреть файл

@ -0,0 +1,50 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* David Haas <haasd@cae.wisc.edu>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import <Appkit/Appkit.h>
@interface ExtendedTableView : NSTableView {
SEL mDeleteAction;
}
-(void)setDeleteAction: (SEL)deleteAction;
-(SEL)deleteAction;
@end

Просмотреть файл

@ -0,0 +1,97 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* David Haas <haasd@cae.wisc.edu>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import "ExtendedTableView.h"
@implementation ExtendedTableView
-(void)setDeleteAction: (SEL)aDeleteAction
{
mDeleteAction = aDeleteAction;
}
-(SEL)deleteAction
{
return mDeleteAction;
}
-(void)keyDown:(NSEvent*)aEvent
{
const unichar kForwardDeleteChar = 0xf728; // couldn't find this in any cocoa header
// check each char in the event array. it should be just 1 char, but
// just in case we use a loop.
int len = [[aEvent characters] length];
for ( int i = 0; i < len; ++i ) {
unichar c = [[aEvent characters] characterAtIndex:i];
// Check for a certain set of special keys.
if (c == NSDeleteCharacter || c == NSBackspaceCharacter || c == kForwardDeleteChar) {
// delete the bookmark
if (mDeleteAction)
[NSApp sendAction: mDeleteAction to: [self target] from: self];
return;
}
}
return [super keyDown: aEvent];
}
-(NSMenu *)menuForEvent:(NSEvent *)theEvent
{
int rowIndex;
NSPoint point;
point = [self convertPoint:[theEvent locationInWindow] fromView:nil];
rowIndex = [self rowAtPoint:point];
if (rowIndex >= 0) {
[self abortEditing];
id delegate = [self delegate];
if (![self isRowSelected:rowIndex]) {
if ([delegate respondsToSelector:@selector(tableView:shouldSelectRow:)]) {
if (![delegate tableView:self shouldSelectRow:rowIndex])
return nil;
}
}
if ([delegate respondsToSelector:@selector(tableView:contextMenuForRow:)])
return [delegate tableView:self contextMenuForRow:rowIndex];
}
return nil;
}
@end

Просмотреть файл

@ -0,0 +1,46 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Chimera code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* David Haas <haasd@cae.wisc.edu>
*
* 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 <Foundation/Foundation.h>
@interface NSArray (ChimeraArrayUtils)
// Packages pointers to BookmarkItems into NSData objects for pasteboard
+(NSArray *)dataArrayFromPointerArrayForMozBookmarkDrop:(NSArray *)dragArray;
// Converts NSData objects on a pasteboard back into pointers to BookmarkItems.
+(NSArray *)pointerArrayFromDataArrayForMozBookmarkDrop:(NSArray *)dragArray;
@end

Просмотреть файл

@ -0,0 +1,66 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Chimera code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* David Haas <haasd@cae.wisc.edu>
*
* 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 "NSArray+Utils.h"
@implementation NSArray (ChimeraArrayUtils)
+(NSArray *)pointerArrayFromDataArrayForMozBookmarkDrop:(NSArray *)dragArray
{
NSMutableArray *fixedArray = [NSMutableArray arrayWithCapacity:[dragArray count]];
NSEnumerator *enumerator = [dragArray objectEnumerator];
id aDataToPointer, aPointerToBookmark;
while ((aDataToPointer = [enumerator nextObject])) {
[aDataToPointer getBytes:&aPointerToBookmark length:(sizeof(id))];
[fixedArray addObject:aPointerToBookmark];
}
return [NSArray arrayWithArray:fixedArray];
}
+(NSArray *)dataArrayFromPointerArrayForMozBookmarkDrop:(NSArray *)dragArray
{
NSMutableArray *dataArray = [NSMutableArray arrayWithCapacity:[dragArray count]];
NSEnumerator *enumerator = [dragArray objectEnumerator];
id aBookmark;
while ((aBookmark = [enumerator nextObject]))
[dataArray addObject:[NSData dataWithBytes:&aBookmark length:(sizeof(id))]];
return [NSArray arrayWithArray:dataArray];
}
@end

Просмотреть файл

@ -52,6 +52,7 @@ typedef enum
@interface NSString (ChimeraStringUtils)
+ (id)ellipsisString;
+ (id)escapedURLString:(NSString *)unescapedString;
+ (id)stringWithPRUnichars:(const PRUnichar*)inString;
+ (id)stringWith_nsAString:(const nsAString&)inString;
- (void)assignTo_nsAString:(nsAString&)ioString;
@ -60,6 +61,9 @@ typedef enum
- (NSString *)stringByReplacingCharactersInSet:(NSCharacterSet*)characterSet withString:(NSString*)string;
- (NSString *)stringByTruncatingTo:(unsigned int)maxCharacters at:(ETruncationType)truncationType;
- (NSString *)stringByTrimmingWhitespace;
-(NSString *)stringByRemovingAmpEscapes;
-(NSString *)stringByAddingAmpEscapes;
-(NSString *)stripWWW;
// allocate a new unicode buffer with the contents of the current string. Caller
// is responsible for freeing the buffer.

Просмотреть файл

@ -20,6 +20,7 @@
*
* Contributor(s):
* Simon Fraser <sfraser@netscape.com>
* David Haas <haasd@cae.wisc.edu>
*
* 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
@ -59,6 +60,12 @@
return sEllipsisString;
}
+ (id)escapedURLString:(NSString *)unescapedString
{
NSString *escapedString = (NSString *) CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)unescapedString, NULL, NULL, kCFStringEncodingUTF8);
return [escapedString autorelease];
}
+ (id)stringWithPRUnichars:(const PRUnichar*)inString
{
if (inString)
@ -167,6 +174,91 @@
return retStr;
}
-(NSString *)stringByRemovingAmpEscapes
{
NSMutableString* dirtyStringMutant = [NSMutableString stringWithString:self];
//10.2 and later
if ([dirtyStringMutant respondsToSelector:@selector(replaceOccurrencesOfString:withString:options:range:)]){
[dirtyStringMutant replaceOccurrencesOfString:@"&amp;"withString:@"&" options:NSLiteralSearch range:NSMakeRange(0,[dirtyStringMutant length])];
[dirtyStringMutant replaceOccurrencesOfString:@"&quot;"withString:@"\"" options:NSLiteralSearch range:NSMakeRange(0,[dirtyStringMutant length])];
[dirtyStringMutant replaceOccurrencesOfString:@"&lt;"withString:@"<" options:NSLiteralSearch range:NSMakeRange(0,[dirtyStringMutant length])];
[dirtyStringMutant replaceOccurrencesOfString:@"&gt;"withString:@">" options:NSLiteralSearch range:NSMakeRange(0,[dirtyStringMutant length])];
[dirtyStringMutant replaceOccurrencesOfString:@"&mdash;"withString:@"-" options:NSLiteralSearch range:NSMakeRange(0,[dirtyStringMutant length])];
return [dirtyStringMutant stringByRemovingCharactersInSet:[NSCharacterSet controlCharacterSet]];
}
// 10.1.
NSRange ampRange = [dirtyStringMutant rangeOfString:@"&amp;" options:NSLiteralSearch];
while (ampRange.location != NSNotFound) {
[dirtyStringMutant replaceCharactersInRange:ampRange withString:@"&"];
ampRange = [dirtyStringMutant rangeOfString:@"&amp;" options:NSLiteralSearch range:NSMakeRange(ampRange.location,[dirtyStringMutant length]-ampRange.location)];
}
ampRange = [dirtyStringMutant rangeOfString:@"&quot;" options:NSLiteralSearch];
while (ampRange.location != NSNotFound) {
[dirtyStringMutant replaceCharactersInRange:ampRange withString:@"\""];
ampRange = [dirtyStringMutant rangeOfString:@"&quot;" options:NSLiteralSearch range:NSMakeRange(ampRange.location,[dirtyStringMutant length]-ampRange.location)];
}
ampRange = [dirtyStringMutant rangeOfString:@"&lt;" options:NSLiteralSearch];
while (ampRange.location != NSNotFound) {
[dirtyStringMutant replaceCharactersInRange:ampRange withString:@"<"];
ampRange = [dirtyStringMutant rangeOfString:@"&lt;" options:NSLiteralSearch range:NSMakeRange(ampRange.location,[dirtyStringMutant length]-ampRange.location)];
}
ampRange = [dirtyStringMutant rangeOfString:@"&gt;" options:NSLiteralSearch];
while (ampRange.location != NSNotFound) {
[dirtyStringMutant replaceCharactersInRange:ampRange withString:@">"];
ampRange = [dirtyStringMutant rangeOfString:@"&gt;" options:NSLiteralSearch range:NSMakeRange(ampRange.location,[dirtyStringMutant length]-ampRange.location)];
}
ampRange = [dirtyStringMutant rangeOfString:@"&mdash;" options:NSLiteralSearch];
while (ampRange.location != NSNotFound) {
[dirtyStringMutant replaceCharactersInRange:ampRange withString:@"-"];
ampRange = [dirtyStringMutant rangeOfString:@"&mdash;" options:NSLiteralSearch range:NSMakeRange(ampRange.location,[dirtyStringMutant length]-ampRange.location)];
}
return [dirtyStringMutant stringByRemovingCharactersInSet:[NSCharacterSet controlCharacterSet]];
}
-(NSString *)stringByAddingAmpEscapes
{
NSMutableString* dirtyStringMutant = [NSMutableString stringWithString:self];
//10.2 & later
if ([dirtyStringMutant respondsToSelector:@selector(replaceOccurrencesOfString:withString:options:range:)]){
[dirtyStringMutant replaceOccurrencesOfString:@"&"withString:@"&amp;" options:NSLiteralSearch range:NSMakeRange(0,[dirtyStringMutant length])];
[dirtyStringMutant replaceOccurrencesOfString:@"\""withString:@"&quot;" options:NSLiteralSearch range:NSMakeRange(0,[dirtyStringMutant length])];
[dirtyStringMutant replaceOccurrencesOfString:@"<"withString:@"&lt;" options:NSLiteralSearch range:NSMakeRange(0,[dirtyStringMutant length])];
[dirtyStringMutant replaceOccurrencesOfString:@">"withString:@"&gt;" options:NSLiteralSearch range:NSMakeRange(0,[dirtyStringMutant length])];
return [NSString stringWithString:dirtyStringMutant];
}
// 10.1.
NSRange ampRange = [dirtyStringMutant rangeOfString:@"&" options:NSLiteralSearch];
while (ampRange.location != NSNotFound) {
[dirtyStringMutant replaceCharactersInRange:ampRange withString:@"&amp;"];
ampRange = [dirtyStringMutant rangeOfString:@"&" options:NSLiteralSearch range:NSMakeRange(ampRange.location+1,[dirtyStringMutant length]-ampRange.location-1)];
}
ampRange = [dirtyStringMutant rangeOfString:@"\"" options:NSLiteralSearch];
while (ampRange.location != NSNotFound) {
[dirtyStringMutant replaceCharactersInRange:ampRange withString:@"&quot;"];
ampRange = [dirtyStringMutant rangeOfString:@"\"" options:NSLiteralSearch range:NSMakeRange(ampRange.location,[dirtyStringMutant length]-ampRange.location)];
}
ampRange = [dirtyStringMutant rangeOfString:@"<" options:NSLiteralSearch];
while (ampRange.location != NSNotFound) {
[dirtyStringMutant replaceCharactersInRange:ampRange withString:@"&lt;"];
ampRange = [dirtyStringMutant rangeOfString:@"<" options:NSLiteralSearch range:NSMakeRange(ampRange.location,[dirtyStringMutant length]-ampRange.location)];
}
ampRange = [dirtyStringMutant rangeOfString:@">" options:NSLiteralSearch];
while (ampRange.location != NSNotFound) {
[dirtyStringMutant replaceCharactersInRange:ampRange withString:@"&gt;"];
ampRange = [dirtyStringMutant rangeOfString:@">" options:NSLiteralSearch range:NSMakeRange(ampRange.location,[dirtyStringMutant length]-ampRange.location)];
}
return [NSString stringWithString:dirtyStringMutant];
}
-(NSString *)stripWWW
{
if ([self hasPrefix:@"www."] && ([self length]>4))
return [self substringFromIndex:4];
return self;
}
@end

Просмотреть файл

@ -36,15 +36,14 @@
*
* ***** END LICENSE BLOCK ***** */
#import <Foundation/Foundation.h>
#import <Appkit/Appkit.h>
#import "ExtendedOutlineView.h"
class nsIRDFDataSource;
class nsIRDFContainer;
class nsIRDFContainerUtils;
class nsIRDFResource;
class nsIRDFService;
@class ExtendedOutlineView;
// RDF Resource Wrapper to make the Outline View happy

Просмотреть файл

@ -40,6 +40,7 @@
#import "RDFOutlineViewDataSource.h"
#import "CHBrowserService.h"
#import "ExtendedOutlineView.h"
#include "nsCRT.h"
#include "nsIRDFDataSource.h"
@ -333,8 +334,12 @@
// The table column's identifier is the last part of the RDF Resource URI of the property
// being displayed in that column, e.g. "http://home.netscape.com/NC-rdf#Name"
// little hack inserted until history moves to new bookmark format
NSString *identifier = [aTableColumn identifier];
if ([identifier isEqualToString:@"title"])
identifier = [NSString stringWithString:@"Name"];
NSString* columnPropertyURI = [NSString stringWithFormat:@"http://home.netscape.com/NC-rdf#%@",
[aTableColumn identifier]];
identifier];
NSString* propString = [self getPropertyString:columnPropertyURI forItem:aItem];
return [self createCellContents:propString withColumn:columnPropertyURI byItem:aItem];

Просмотреть файл

@ -36,8 +36,6 @@
*
* ***** END LICENSE BLOCK ***** */
#import <Foundation/Foundation.h>
#import "RDFOutlineViewDataSource.h"
class nsAString;

Просмотреть файл

@ -41,6 +41,7 @@
#import "BrowserWindowController.h"
#import "HistoryDataSource.h"
#import "CHBrowserView.h"
#import "ExtendedOutlineView.h"
#include "nsIRDFService.h"
#include "nsIRDFDataSource.h"
@ -265,7 +266,8 @@ HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*,
//
-(id) createCellContents:(NSString*)inValue withColumn:(NSString*)inColumn byItem:(id) inItem
{
if ([inValue length] == 0)
NSString *fragment = [[NSURL URLWithString:inColumn] fragment];
if (([inValue length] == 0) && [fragment isEqualToString:@"Name"])
inValue = [self getPropertyString:@"http://home.netscape.com/NC-rdf#URL" forItem:inItem];
return inValue;
}
@ -430,7 +432,7 @@ HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*,
- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(NSCell *)inCell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
// set the image on the name column. the url column doesn't have an image.
if ([[tableColumn identifier] isEqualToString: @"Name"]) {
if ([[tableColumn identifier] isEqualToString: @"title"]) {
if ( [outlineView isExpandable: item] )
[inCell setImage:[NSImage imageNamed:@"folder"]];
else

Просмотреть файл

@ -45,9 +45,9 @@
@protocol NetworkServicesClient
- (void)availableServicesChanged:(NetworkServices*)servicesProvider;
- (void)serviceResolved:(int)serviceID withURL:(NSString*)url;
- (void)serviceResolutionFailed:(int)serviceID;
- (void)availableServicesChanged:(NSNotification *)note;
- (void)serviceResolved:(NSNotification *)note;
- (void)serviceResolutionFailed:(NSNotification *)note;
@end
@ -60,22 +60,27 @@
NSNetServiceBrowser* mFtpBrowser;
int mCurServiceID; // unique ID for each service
NSMutableDictionary* mNetworkServices; // services keyed by ID
NSMutableDictionary* mNetworkServices; // services keyed by ID
NSMutableArray* mClients; // array of id<NetworkServicesClient>
NSMutableDictionary* mClients; // dictionary of cliend id's for a request
}
+ (id)sharedNetworkServices;
+ (void)shutdownNetworkServices;
- (void)startServices;
- (void)stopServices;
- (void)registerClient:(id<NetworkServicesClient>)client;
- (void)unregisterClient:(id<NetworkServicesClient>)client;
- (void)attemptResolveService:(int)serviceID;
- (void)attemptResolveService:(int)serviceID forSender:(id)aSender;
- (NSString*)serviceName:(int)serviceID;
- (NSString*)serviceProtocol:(int)serviceID;
- (NSEnumerator*)serviceEnumerator;
// Notifications
extern NSString *NetworkServicesAvailableServicesChanged;
extern NSString *NetworkServicesResolutionSuccess;
extern NSString *NetworkServicesResolutionFailure;
extern NSString *NetworkServicesClientKey;
extern NSString *NetworkServicesResolvedURLKey;
extern NSString *NetworkServicesServiceKey;
@end

Просмотреть файл

@ -21,6 +21,7 @@
*
* Contributor(s):
* Simon Fraser <sfraser@netscape.com>
* David Haas <haasd@cae.wisc.edu>
*
*
* Alternatively, the contents of this file may be used under the terms of
@ -51,6 +52,14 @@
@class NSNetServiceBrowser;
// client notifications
NSString *NetworkServicesAvailableServicesChanged = @"netserv_asc";
NSString *NetworkServicesResolutionSuccess = @"netserv_resok";
NSString *NetworkServicesClientKey = @"netserv_clikey";
NSString *NetworkServicesResolvedURLKey = @"netserv_urlkey";
NSString *NetworkServicesResolutionFailure = @"netserv_resbad";
NSString *NetworkServicesServiceKey = @"netserv_srvkey";
@interface NetworkServices(Private)
@ -59,25 +68,39 @@
- (void)notifyClientsOfServicesChange;
- (void)notifyClientsOfServiceResolution:(int)serviceID withURL:(NSString*)url;
- (void)notifyClientsOfServiceResolutionFailure:(int)serviceID;
- (void)notifyClientsOfServiceResolution:(NSNetService *)aService withURL:(NSString*)url;
- (void)notifyClientsOfServiceResolutionFailure:(NSNetService *)aService;
- (void)serviceAppeared:(NSNetService*)service;
- (void)serviceDisappeared:(NSNetService*)service;
- (void)serviceResolved:(NSNetService*)service;
- (int)getServiceID:(NSNetService*)service;
@end
@implementation NetworkServices
static NetworkServices* gNetworkServices = nil;
+(id)sharedNetworkServices
{
if (!gNetworkServices)
gNetworkServices = [[NetworkServices alloc] init];
return gNetworkServices;
}
+(void)shutdownNetworkServices
{
[gNetworkServices release]; //this'll put the hammer on things
}
- (id)init
{
if ((self = [super init]))
{
mNetworkServices = [[NSMutableDictionary alloc] initWithCapacity:5];
mClients = [[NSMutableDictionary alloc] initWithCapacity:2];
mCurServiceID = 0;
[self setupNetworkBrowsers];
}
return self;
@ -88,6 +111,8 @@
[self stopServices];
[mNetworkServices release];
[mClients release];
if (self == gNetworkServices)
gNetworkServices = nil;
[super dealloc];
}
@ -120,20 +145,6 @@
}
}
- (void)registerClient:(id<NetworkServicesClient>)client
{
if (!mClients)
mClients = [[NSMutableArray alloc] initWithCapacity:2];
if ([mClients indexOfObject:client] == NSNotFound)
[mClients addObject:client];
}
- (void)unregisterClient:(id<NetworkServicesClient>)client
{
[mClients removeObject:client];
}
- (NSString*)serviceName:(int)serviceID
{
NSNetService* service = [mNetworkServices objectForKey:[NSNumber numberWithInt:serviceID]];
@ -150,11 +161,12 @@
return [service type];
}
- (void)attemptResolveService:(int)serviceID
- (void)attemptResolveService:(int)serviceID forSender:(id)aSender;
{
NSNetService* service = [mNetworkServices objectForKey:[NSNumber numberWithInt:serviceID]];
NSNumber *serviceKey = [NSNumber numberWithInt:serviceID];
NSNetService* service = [mNetworkServices objectForKey:serviceKey];
if (!service) return;
[mClients setObject:aSender forKey:serviceKey];
[service resolve];
}
@ -165,13 +177,6 @@
#pragma mark -
- (int)getServiceID:(NSNetService*)service
{
NSArray* serviceKeys = [mNetworkServices allKeysForObject:service];
// there should only ever be one key
return [[serviceKeys objectAtIndex:0] intValue];
}
- (void)setupNetworkBrowsers
{
mHttpBrowser = [[NSNetServiceBrowser alloc] init];
@ -190,33 +195,27 @@
- (void)notifyClientsOfServicesChange
{
for (unsigned int i = 0; i < [mClients count]; i ++)
{
id<NetworkServicesClient> client = [mClients objectAtIndex:i];
[client availableServicesChanged:self];
}
NSNotification *note = [NSNotification notificationWithName:NetworkServicesAvailableServicesChanged object:self userInfo:nil];
NSNotificationQueue *nc = [NSNotificationQueue defaultQueue];
[nc enqueueNotification:note postingStyle:NSPostWhenIdle coalesceMask:NSNotificationCoalescingOnName forModes:[NSArray arrayWithObject:NSDefaultRunLoopMode]];
}
- (void)notifyClientsOfServiceResolution:(int)serviceID withURL:(NSString*)url
- (void)notifyClientsOfServiceResolution:(NSNetService *)aService withURL:(NSString*)url
{
// ldeally we'd keep track of which client issued the attemptResolveService
// request, and only give it the callback. But we don't do that yet.
for (unsigned int i = 0; i < [mClients count]; i ++)
{
id<NetworkServicesClient> client = [mClients objectAtIndex:i];
[client serviceResolved:serviceID withURL:url];
}
NSNumber *serviceKey = [[mNetworkServices allKeysForObject:aService] objectAtIndex:0];
id aClient = [mClients objectForKey:serviceKey];
NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:aClient,NetworkServicesClientKey,url,NetworkServicesResolvedURLKey,[aService name],NetworkServicesServiceKey,nil];
[[NSNotificationCenter defaultCenter] postNotificationName:NetworkServicesResolutionSuccess object:self userInfo:userInfo];
[mClients removeObjectForKey:aService];
}
- (void)notifyClientsOfServiceResolutionFailure:(int)serviceID
- (void)notifyClientsOfServiceResolutionFailure:(NSNetService *)aService
{
// ldeally we'd keep track of which client issued the attemptResolveService
// request, and only give it the callback. But we don't do that yet.
for (unsigned int i = 0; i < [mClients count]; i ++)
{
id<NetworkServicesClient> client = [mClients objectAtIndex:i];
[client serviceResolutionFailed:serviceID];
}
NSNumber *serviceKey = [[mNetworkServices allKeysForObject:aService] objectAtIndex:0];
id aClient = [mClients objectForKey:serviceKey];
NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:aClient, NetworkServicesClientKey, [aService name],NetworkServicesServiceKey,nil];
[[NSNotificationCenter defaultCenter] postNotificationName:NetworkServicesResolutionFailure object:self userInfo:userInfo];
[mClients removeObjectForKey:aService];
}
- (void)serviceAppeared:(NSNetService*)service
@ -365,7 +364,7 @@ static inline u_int ns_get16(u_char* buffer)
else
urlString = [NSString stringWithFormat:@"%s//%s:%u%s", protocol, escapedTarget, port, pathBuffer];
[self notifyClientsOfServiceResolution:[self getServiceID:netService] withURL:urlString];
[self notifyClientsOfServiceResolution:netService withURL:urlString];
return;
}
}
@ -373,7 +372,7 @@ static inline u_int ns_get16(u_char* buffer)
}
// only get here on failure
[self notifyClientsOfServiceResolutionFailure:[self getServiceID:netService]];
[self notifyClientsOfServiceResolutionFailure:netService];
}
- (void)netServiceDidResolveAddress:(NSNetService *)netService
@ -385,7 +384,7 @@ static inline u_int ns_get16(u_char* buffer)
- (void)netService:(NSNetService *)sender didNotResolve:(NSDictionary *)errorDict
{
[self notifyClientsOfServiceResolutionFailure:[self getServiceID:sender]];
[self notifyClientsOfServiceResolutionFailure:sender];
// now clear out the state of the service
[sender stop];
}
@ -401,8 +400,7 @@ static inline u_int ns_get16(u_char* buffer)
{
[self serviceAppeared:aNetService];
[aNetService setDelegate:self];
// rebuild the menu
// trigger notification
if (!moreComing)
[self notifyClientsOfServicesChange];
}