/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ #include "stdafx.h" #include "usertlbr.h" #include "shcut.h" #include "dropmenu.h" #include "prefapi.h" #include "rdfliner.h" extern "C" { #include "xpgetstr.h" }; #define LEFT_TOOLBAR_MARGIN 10 #define RIGHT_TOOLBAR_MARGIN 20 #define SPACE_BETWEEN_BUTTONS 2 #define MAX_TOOLBAR_BUTTONS 60 #define MAX_TOOLBAR_ROWS 3 int CRDFToolbar::m_nMinToolbarButtonChars = 15; int CRDFToolbar::m_nMaxToolbarButtonChars = 30; ////////////////////////////////////////////////////////////////////////////////////// // CRDFToolbarButtonDropTarget ////////////////////////////////////////////////////////////////////////////////////// DROPEFFECT CRDFToolbarButtonDropTarget::ProcessDragEnter(CWnd *pWnd, COleDataObject *pDataObject, DWORD dwKeyState, CPoint point) { // Drop target is only used for drops directly onto folder personal toolbar buttons. // This drop target is NOT used for the Aurora selector bar drops. return ProcessDragOver(pWnd, pDataObject, dwKeyState, point); } DROPEFFECT CRDFToolbarButtonDropTarget::ProcessDragOver(CWnd *pWnd, COleDataObject *pDataObject, DWORD dwKeyState, CPoint point) { CRDFToolbarButton* pButton = (CRDFToolbarButton*)m_pButton; // Treat as a drop onto the folder. return RDFGLOBAL_TranslateDropAction(pButton->GetNode(), pDataObject, 2); } BOOL CRDFToolbarButtonDropTarget::ProcessDrop(CWnd *pWnd, COleDataObject *pDataObject, DROPEFFECT dropEffect, CPoint point) { // Treat as a drop onto the folder. CRDFToolbarButton* pButton = (CRDFToolbarButton*)m_pButton; RDFGLOBAL_PerformDrop(pDataObject, pButton->GetNode(), 2); return TRUE; } ////////////////////////////////////////////////////////////////////////////////////// // CRDFToolbarButton ////////////////////////////////////////////////////////////////////////////////////// static HBITMAP m_hbmpBM = NULL; static HBITMAP m_hbmpBMSelected = NULL; static HBITMAP m_hbmpFolder = NULL; static HBITMAP m_hbmpSelectedFolder = NULL; static HBITMAP m_hbmpFolderOpen = NULL; static int nBitmapRefCount = 0; CRDFToolbarButton::CRDFToolbarButton() { m_bShouldShowRMMenu = TRUE; m_Node = NULL; m_uCurBMID = 0; currentRow = 0; } CRDFToolbarButton::~CRDFToolbarButton() { if(m_Node && HT_IsContainer(m_Node)) { nBitmapRefCount--; if(nBitmapRefCount == 0) { if(m_hbmpBM) { DeleteObject(m_hbmpBM); } if(m_hbmpFolder) { DeleteObject(m_hbmpFolder); } if(m_hbmpSelectedFolder) { DeleteObject(m_hbmpSelectedFolder); } if(m_hbmpFolderOpen) { DeleteObject(m_hbmpFolderOpen); } if(m_hbmpBMSelected) { DeleteObject(m_hbmpBMSelected); } } } } int CRDFToolbarButton::Create(CWnd *pParent, int nToolbarStyle, CSize noviceButtonSize, CSize advancedButtonSize, LPCTSTR pButtonText, LPCTSTR pToolTipText, LPCTSTR pStatusText, CSize bitmapSize, int nMaxTextChars, int nMinTextChars, BOOKMARKITEM bookmark, HT_Resource pNode, DWORD dwButtonStyle ) { m_bookmark = bookmark; char *protocol = NULL; BOOL bResult = CToolbarButton::Create(pParent, nToolbarStyle, noviceButtonSize, advancedButtonSize, pButtonText, pToolTipText, pStatusText, 0, 0, bitmapSize, TRUE, 0, nMaxTextChars, nMinTextChars, dwButtonStyle); if(bResult) { SetNode(pNode); m_nIconType = DetermineIconType(pNode, UseLargeIcons()); m_nBitmapID = GetBitmapID(); m_nBitmapIndex = GetBitmapIndex(); HDC hDC = ::GetDC(m_hWnd); HPALETTE hPalette = WFE_GetUIPalette(GetParentFrame()); HBITMAP hBitmap = WFE_LookupLoadAndEnterBitmap(hDC, m_nBitmapID, TRUE, hPalette, sysInfo.m_clrBtnFace, RGB(255, 0, 255)); ::ReleaseDC(m_hWnd, hDC); SetBitmap(hBitmap, TRUE); if (m_menu.m_hMenu == NULL || (m_menu.m_hMenu != NULL && !IsMenu(m_menu.m_hMenu))) m_menu.CreatePopupMenu(); } return bResult; } CSize CRDFToolbarButton::GetMinimalButtonSize(void) { CString szText(HT_GetNodeName(m_Node)); return GetButtonSizeFromChars(szText, m_nMinTextChars); } CSize CRDFToolbarButton::GetMaximalButtonSize(void) { CString szText(HT_GetNodeName(m_Node)); return GetButtonSizeFromChars(szText, m_nMaxTextChars); } void CRDFToolbarButton::OnAction(void) { if(m_Node && !HT_IsContainer(m_Node)) { CAbstractCX * pCX = FEU_GetLastActiveFrameContext(); ASSERT(pCX != NULL); if (pCX != NULL) { if (!HT_Launch(m_Node, pCX->GetContext())) pCX->NormalGetUrl((LPTSTR)HT_GetNodeURL(m_Node)); } } } void CRDFToolbarButton::FillInOleDataSource(COleDataSource *pDataSource) { CLIPFORMAT cfHTNode = (CLIPFORMAT)RegisterClipboardFormat(NETSCAPE_HTNODE_FORMAT); HANDLE hString = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE,1); pDataSource->CacheGlobalData(cfHTNode, hString); // Need to "select" the button in the view. Hack. HT_SetSelection(m_Node); // Now the view is sufficient RDFGLOBAL_BeginDrag(pDataSource, HT_GetView(m_Node)); } BOOKMARKITEM CRDFToolbarButton::GetBookmarkItem(void) { return m_bookmark; } void CRDFToolbarButton::SetBookmarkItem(BOOKMARKITEM bookmark) { /* m_bookmark = bookmark; CString strText(bookmark.szText); CToolbarButton::SetText(strText); */ } void CRDFToolbarButton::SetNode(HT_Resource pNode, BOOL bAddRef) { if (pNode == NULL) return; m_Node = pNode; // if it's a header and we haven't already loaded the bitmaps, load the bitmaps if(HT_IsContainer(pNode) && bAddRef) { HDC hDC = ::GetDC(m_hWnd); HINSTANCE hInstance = AfxGetResourceHandle(); WFE_InitializeUIPalette(hDC); HPALETTE hPalette = WFE_GetUIPalette(GetParentFrame()); if(nBitmapRefCount == 0) { m_hbmpBM = WFE_LoadTransparentBitmap(hInstance, hDC, sysInfo.m_clrMenu, RGB(255, 0, 255), hPalette, IDB_BOOKMARK_ITEM); m_hbmpBMSelected = WFE_LoadTransparentBitmap(hInstance, hDC,sysInfo.m_clrHighlight, RGB(255, 0, 255), hPalette, IDB_BOOKMARK_ITEM); m_hbmpFolder = WFE_LoadTransparentBitmap(hInstance, hDC,sysInfo.m_clrMenu, RGB(255, 0, 255), hPalette, IDB_BOOKMARK_FOLDER2); m_hbmpSelectedFolder = WFE_LoadTransparentBitmap(hInstance, hDC, sysInfo.m_clrHighlight, RGB(255, 0, 255), hPalette, IDB_BOOKMARK_FOLDER2); m_hbmpFolderOpen = WFE_LoadTransparentBitmap(hInstance, hDC, sysInfo.m_clrHighlight, RGB(255, 0, 255), hPalette, IDB_BOOKMARK_FOLDER_OPEN); } nBitmapRefCount++; ::ReleaseDC(m_hWnd, hDC); } } void CRDFToolbarButton::EditTextChanged(char *pText) { if (pText) { HT_SetNodeName(m_Node, pText); SetText(pText); SetToolTipText(pText); delete []pText; } RemoveTextEdit(); ((CRDFToolbar*)GetParent())->LayoutButtons(-1); } void CRDFToolbarButton::DrawPicturesAndTextMode(HDC hDC, CRect rect) { DrawBitmapOnSide(hDC, rect); } void CRDFToolbarButton::DrawPicturesMode(HDC hDC, CRect rect) { DrawBitmapOnSide(hDC, rect); } void CRDFToolbarButton::DrawButtonText(HDC hDC, CRect rcTxt, CSize sizeTxt, CString strTxt) { CToolbarButton::DrawButtonText(hDC, rcTxt, sizeTxt, strTxt); } CSize CRDFToolbarButton::GetButtonSizeFromChars(CString s, int c) { if(m_nToolbarStyle != TB_TEXT) return(GetBitmapOnSideSize(s, c)); else return(GetTextOnlySize(s, c)); } void CRDFToolbarButton::GetPicturesAndTextModeTextRect(CRect &rect) { GetBitmapOnSideTextRect(rect); } void CRDFToolbarButton::GetPicturesModeTextRect(CRect &rect) { GetBitmapOnSideTextRect(rect); } BOOL CRDFToolbarButton::CreateRightMouseMenu(void) { if (m_bShouldShowRMMenu) { m_MenuCommandMap.Clear(); HT_SetSelection(m_Node); // Make sure the node is the selection in the view. HT_View theView = HT_GetView(m_Node); HT_Cursor theCursor = HT_NewContextualMenuCursor(theView, PR_FALSE, PR_FALSE); if (theCursor != NULL) { // We have a cursor. Attempt to iterate HT_MenuCmd theCommand; while (HT_NextContextMenuItem(theCursor, &theCommand)) { char* menuName = HT_GetMenuCmdName(theCommand); if (theCommand == HT_CMD_SEPARATOR) m_menu.AppendMenu(MF_SEPARATOR); else { // Add the command to our command map CRDFMenuCommand* rdfCommand = new CRDFMenuCommand(menuName, theCommand); int index = m_MenuCommandMap.AddCommand(rdfCommand); m_menu.AppendMenu(MF_ENABLED, index+FIRST_HT_MENU_ID, menuName); } } HT_DeleteCursor(theCursor); } } return m_bShouldShowRMMenu; } CWnd* CRDFToolbarButton::GetMenuParent(void) { return this; } BOOL CRDFToolbarButton::OnCommand(UINT wParam, LONG lParam) { BOOL bRtn = TRUE; if (wParam >= FIRST_HT_MENU_ID && wParam <= LAST_HT_MENU_ID) { // A selection was made from the context menu. // Use the menu map to get the HT command value CRDFMenuCommand* theCommand = (CRDFMenuCommand*)(m_MenuCommandMap.GetCommand((int)wParam-FIRST_HT_MENU_ID)); if (theCommand) { HT_MenuCmd htCommand = theCommand->GetHTCommand(); HT_DoMenuCmd(HT_GetPane(GetHTView()), htCommand); } return bRtn; } if(wParam == ID_HOTLIST_VIEW || wParam == ID_HOTLIST_ADDCURRENTTOHOTLIST) { GetParentFrame()->SendMessage(WM_COMMAND, wParam, lParam); } else if(wParam == ID_DELETE_BUTTON) { HT_RemoveChild(HT_GetParent(m_Node), m_Node); } else if(wParam == ID_BUTTON_PROPERTIES) { // PROPERTIES } else if(wParam == ID_RENAME_BUTTON) { AddTextEdit(); SetTextEditText(m_pButtonText); } // Only interested in commands from bookmark quick file menu else if ((wParam >= FIRST_BOOKMARK_MENU_ID)) { void * pBookmark = NULL; m_BMMenuMap.Lookup(wParam, pBookmark); if (pBookmark != NULL) { HT_Resource theNode = (HT_Resource)pBookmark; CAbstractCX *pCX = FEU_GetLastActiveFrameContext(); ASSERT(pCX != NULL); if (pCX != NULL) { if (!HT_Launch(theNode, pCX->GetContext())) pCX->NormalGetUrl((LPTSTR)HT_GetNodeURL(theNode)); } } } else { bRtn = CRDFToolbarButtonBase::OnCommand(wParam, lParam); } return(bRtn); } /////////////////////////////////////////////////////////////////////////////////// // CRDFToolbarButton Messages /////////////////////////////////////////////////////////////////////////////////// BEGIN_MESSAGE_MAP(CRDFToolbarButton, CRDFToolbarButtonBase) //{{AFX_MSG_MAP(CRDFToolbarButton) ON_MESSAGE(NSDRAGMENUOPEN, OnDragMenuOpen) ON_MESSAGE(DM_FILLINMENU, OnFillInMenu) ON_MESSAGE(DT_DROPOCCURRED, OnDropMenuDropOccurred) ON_MESSAGE(DT_DRAGGINGOCCURRED, OnDropMenuDraggingOccurred) ON_MESSAGE(DM_MENUCLOSED, OnDropMenuClosed) ON_WM_SYSCOLORCHANGE() //}}AFX_MSG_MAP END_MESSAGE_MAP() LRESULT CRDFToolbarButton::OnDragMenuOpen(WPARAM wParam, LPARAM lParam) { // Set our drop menu's user data. if (m_pDropMenu) m_pDropMenu->SetUserData(m_Node); if(m_Node == NULL || !HT_IsContainer(m_Node)) return 1; m_uCurBMID = FIRST_BOOKMARK_MENU_ID; m_pCachedDropMenu = (CDropMenu *)lParam; // Set our drop menu PRBool isOpen; HT_Resource theNode = (HT_Resource)m_pCachedDropMenu->GetUserData(); HT_GetOpenState(theNode, &isOpen); if (isOpen) FillInMenu(theNode); else HT_SetOpenState(theNode, (PRBool)TRUE); return 1; } LRESULT CRDFToolbarButton::OnFillInMenu(WPARAM wParam, LPARAM lParam) { // Set our drop menu's user data. if (m_pDropMenu) m_pDropMenu->SetUserData(m_Node); m_pCachedDropMenu = (CDropMenu *)lParam; // Set our drop menu PRBool isOpen; HT_Resource theNode = (HT_Resource)m_pCachedDropMenu->GetUserData(); HT_GetOpenState(theNode, &isOpen); if (isOpen) FillInMenu(theNode); else HT_SetOpenState(theNode, (PRBool)TRUE); return 1; } LRESULT CRDFToolbarButton::OnDropMenuDraggingOccurred(WPARAM wParam, LPARAM lParam) { CDropMenuDragData* pData = (CDropMenuDragData*)lParam; UINT nCommand = pData->m_nCommand; MenuSelectionType eSelType = pData->eSelType; void * pBookmarkInsertAfter = NULL; m_BMMenuMap.Lookup(nCommand, pBookmarkInsertAfter); HT_Resource theNode = (HT_Resource)pBookmarkInsertAfter; int dragFraction = 2; if (eSelType == eON) dragFraction = 2; else if (eSelType == eBELOW) dragFraction = 3; else if (eSelType == eABOVE) dragFraction = 1; // Next we get the result. DROPEFFECT answer = RDFGLOBAL_TranslateDropAction(theNode, pData->m_pDataSource, dragFraction); // Place the result into our data structure for the droptarget to use. pData->m_DropEffect = answer; return 1; } LRESULT CRDFToolbarButton::OnDropMenuDropOccurred(WPARAM wParam, LPARAM lParam) { CDropMenuDragData* pData = (CDropMenuDragData*)lParam; UINT nCommand = pData->m_nCommand; MenuSelectionType eSelType = pData->eSelType; void * pBookmarkInsertAfter = NULL; m_BMMenuMap.Lookup(nCommand, pBookmarkInsertAfter); HT_Resource theNode = (HT_Resource)pBookmarkInsertAfter; int dragFraction = 2; if (eSelType == eON) dragFraction = 2; else if (eSelType == eBELOW) dragFraction = 3; else if (eSelType == eABOVE) dragFraction = 1; RDFGLOBAL_PerformDrop(pData->m_pDataSource, theNode, dragFraction); delete pData; // Clean this structure up. return 1; } LRESULT CRDFToolbarButton::OnDropMenuClosed(WPARAM wParam, LPARAM lParam) { int nCount; if(m_pDropMenu != NULL) { HT_Resource theNode = (HT_Resource)m_pDropMenu->GetUserData(); nCount = m_pDropMenu->GetMenuItemCount(); // clean out the menu for(int i = nCount - 1; i >= 0; i--) { m_pDropMenu->DeleteMenu(i, MF_BYPOSITION); } m_pDropMenu->DestroyDropMenu(); delete m_pDropMenu; m_pDropMenu = NULL; if (theNode != NULL) HT_SetOpenState(theNode, (PRBool)FALSE); } return 1; } void CRDFToolbarButton::OnSysColorChange( ) { if(nBitmapRefCount > 0) { VERIFY(::DeleteObject(m_hbmpBM)); VERIFY(::DeleteObject(m_hbmpBMSelected)); VERIFY(::DeleteObject(m_hbmpFolder)); VERIFY(::DeleteObject(m_hbmpSelectedFolder)); VERIFY(::DeleteObject(m_hbmpFolderOpen)); HINSTANCE hInstance = AfxGetResourceHandle(); HDC hDC = ::GetDC(m_hWnd); WFE_InitializeUIPalette(hDC); HPALETTE hPalette = WFE_GetUIPalette(GetParentFrame()); m_hbmpBM = WFE_LoadTransparentBitmap(hInstance, hDC, sysInfo.m_clrMenu, RGB(255, 0, 255), hPalette, IDB_BOOKMARK_ITEM); m_hbmpBMSelected = WFE_LoadTransparentBitmap(hInstance, hDC,sysInfo.m_clrHighlight, RGB(255, 0, 255), hPalette, IDB_BOOKMARK_ITEM); m_hbmpFolder = WFE_LoadTransparentBitmap(hInstance, hDC,sysInfo.m_clrMenu, RGB(255, 0, 255), hPalette, IDB_BOOKMARK_FOLDER2); m_hbmpSelectedFolder = WFE_LoadTransparentBitmap(hInstance, hDC,sysInfo.m_clrHighlight, RGB(255, 0, 255), hPalette, IDB_BOOKMARK_FOLDER2); m_hbmpFolderOpen = WFE_LoadTransparentBitmap(hInstance, hDC, sysInfo.m_clrHighlight, RGB(255, 0, 255), hPalette, IDB_BOOKMARK_FOLDER_OPEN); ::ReleaseDC(m_hWnd, hDC); } if(m_bBitmapFromParent) { HDC hDC = ::GetDC(m_hWnd); HPALETTE hPalette = WFE_GetUIPalette(GetParentFrame()); HBITMAP hBitmap = WFE_LookupLoadAndEnterBitmap(hDC, m_nBitmapID, TRUE, hPalette, sysInfo.m_clrBtnFace, RGB(255, 0, 255)); ::ReleaseDC(m_hWnd, hDC); SetBitmap(hBitmap, TRUE); } CToolbarButton::OnSysColorChange(); } /////////////////////////////////////////////////////////////////////////// // CRDFToolbarButton Helpers /////////////////////////////////////////////////////////////////////////// void CRDFToolbarButton::FillInMenu(HT_Resource theNode) { m_pCachedDropMenu->CreateOverflowMenuItem(ID_HOTLIST_VIEW, CString(szLoadString(IDS_MORE_BOOKMARKS)), NULL, NULL ); HT_Cursor theCursor = HT_NewCursor(theNode); HT_Resource theItem = NULL; while (theItem = HT_GetNextItem(theCursor)) { IconType nIconType = DetermineIconType(theItem, FALSE); void* pCustomIcon = NULL; if (nIconType == LOCAL_FILE) pCustomIcon = FetchLocalFileIcon(theItem); else if (nIconType == ARBITRARY_URL) pCustomIcon = FetchCustomIcon(theItem, m_pCachedDropMenu, FALSE); HT_SetNodeFEData(theItem, this); if (HT_IsContainer(theItem)) { CDropMenu *pSubMenu = new CDropMenu; pSubMenu->SetUserData(theItem); CString csAmpersandString = FEU_EscapeAmpersand(HT_GetNodeName(theItem)); m_pCachedDropMenu->AppendMenu(MF_POPUP, m_uCurBMID, pSubMenu, FALSE, csAmpersandString, TRUE, m_hbmpFolder, m_hbmpFolderOpen, pCustomIcon, nIconType); m_BMMenuMap.SetAt(m_uCurBMID, theItem); m_uCurBMID++; } else if (!HT_IsSeparator(theItem)) { CString csAmpersandString = FEU_EscapeAmpersand(HT_GetNodeName(theItem)); m_pCachedDropMenu->AppendMenu(MF_STRING, m_uCurBMID, csAmpersandString, TRUE, m_hbmpBM, m_hbmpBMSelected, pCustomIcon, nIconType); m_BMMenuMap.SetAt(m_uCurBMID, theItem); m_uCurBMID++; } else { m_pCachedDropMenu->AppendMenu(MF_SEPARATOR, 0, TRUE, NULL, NULL); } } HT_DeleteCursor(theCursor); m_pCachedDropMenu = NULL; } UINT CRDFToolbarButton::GetBitmapID(void) { if (m_nBitmapID != 0) return m_nBitmapID; if (m_Node && HT_IsContainer(m_Node)) return IDB_BUTTON_FOLDER; else return IDB_USERBTN; } UINT CRDFToolbarButton::GetBitmapIndex(void) { return 0; } void CRDFToolbarButton::SetTextWithoutResize(CString text) { if(m_pButtonText != NULL) { XP_FREE(m_pButtonText); } m_pButtonText = (LPTSTR)XP_ALLOC(text.GetLength() +1); XP_STRCPY(m_pButtonText, text); } void CRDFToolbarButton::LoadComplete(HT_Resource r) { Invalidate(); } void CRDFToolbarButton::DrawCustomIcon(HDC hDC, int x, int y) { int size = UseLargeIcons() ? 23 : 16; DrawArbitraryURL(m_Node, x, y, size, size, hDC, m_bDepressed ? (::GetSysColor(COLOR_BTNSHADOW)) : (::GetSysColor(COLOR_BTNFACE)), this, UseLargeIcons()); } void CRDFToolbarButton::DrawLocalIcon(HDC hDC, int x, int y) { if (m_Node) DrawLocalFileIcon(m_Node, x, y, hDC); } /////////////////////////////////////////////////////////////////////////// // Class CRDFToolbarDropTarget /////////////////////////////////////////////////////////////////////////// void CRDFToolbarDropTarget::Toolbar(CRDFToolbar *pToolbar) { m_pToolbar = pToolbar; } DROPEFFECT CRDFToolbarDropTarget::OnDragEnter(CWnd * pWnd, COleDataObject * pDataObject, DWORD dwKeyState, CPoint point) { return OnDragOver(pWnd, pDataObject, dwKeyState, point); } DROPEFFECT CRDFToolbarDropTarget::OnDragOver(CWnd * pWnd, COleDataObject * pDataObject, DWORD dwKeyState, CPoint point ) { int nStartX = 0; RECT buttonRect; int currentRow = 0; CRDFToolbarButton* pButton = NULL; for(int i = 0; i < m_pToolbar->GetNumButtons(); i++) { pButton = (CRDFToolbarButton*)(m_pToolbar->GetNthButton(i)); pButton->GetClientRect(&buttonRect); pButton->MapWindowPoints(m_pToolbar, &buttonRect); nStartX += (buttonRect.right - buttonRect.left) + SPACE_BETWEEN_BUTTONS; if (currentRow != pButton->GetRow()) { currentRow++; nStartX = LEFT_TOOLBAR_MARGIN + (buttonRect.right - buttonRect.left) + SPACE_BETWEEN_BUTTONS; } if(point.x < nStartX && (point.y >= buttonRect.top && point.y <= buttonRect.bottom)) break; pButton = NULL; } HT_Resource theNode = pButton ? pButton->GetNode() : HT_TopNode(HT_GetSelectedView(m_pToolbar->GetPane())); m_pToolbar->SetDragButton(pButton); if (pButton == NULL) m_pToolbar->SetDragFraction(2); else { // Do the whole computation of drag fraction. Cache our drag fraction and button. CRect rect; pButton->GetClientRect(&rect); if (HT_IsContainer(pButton->GetNode())) { if (point.x <= rect.Width()/3) m_pToolbar->SetDragFraction(1); else if (point.x <= 2*(rect.Width()/3)) m_pToolbar->SetDragFraction(2); else m_pToolbar->SetDragFraction(3); } else if (point.x <= rect.Width()/2) m_pToolbar->SetDragFraction(1); else m_pToolbar->SetDragFraction(2); } return RDFGLOBAL_TranslateDropAction(theNode, pDataObject, m_pToolbar->GetDragFraction()); } BOOL CRDFToolbarDropTarget::OnDrop(CWnd * pWnd, COleDataObject * pDataObject, DROPEFFECT dropEffect, CPoint point) { HT_Resource theNode = HT_TopNode(HT_GetSelectedView(m_pToolbar->GetPane())); if (m_pToolbar->GetDragButton()) theNode = m_pToolbar->GetDragButton()->GetNode(); RDFGLOBAL_PerformDrop(pDataObject, theNode, m_pToolbar->GetDragFraction()); return TRUE; } // End CRDFToolbarDropTarget implementation /////////////////////////////////////////////////////////////////////////// // Class CRDFToolbar /////////////////////////////////////////////////////////////////////////// #define LINKTOOLBARHEIGHT 21 #define SPACE_BETWEEN_ROWS 2 // The Event Handler for HT notifications on the personal toolbar static void ptNotifyProcedure (HT_Notification ns, HT_Resource n, HT_Event whatHappened) { CRDFToolbar* theToolbar = (CRDFToolbar*)ns->data; if (n != NULL) { HT_View theView = HT_GetView(n); if (theView != NULL) { if (whatHappened == HT_EVENT_NODE_OPENCLOSE_CHANGED) { PRBool openState; HT_GetOpenState(n, &openState); if (openState) { if (n == HT_TopNode(theView)) { // Initial population of the toolbar. We should only receive this event once. theToolbar->FillInToolbar(); } else { // Toolbar button menu. Populate it. CRDFToolbarButton* theButton = (CRDFToolbarButton*)(HT_GetNodeFEData(n)); theButton->FillInMenu(n); } } } else if (whatHappened == HT_EVENT_VIEW_REFRESH) { theToolbar->LayoutButtons(-1); } else if (HT_TopNode(theView) == HT_GetParent(n)) { // Aside from the opening/closing, we only respond to events that occurred on the top node of // the view or the immediate children (the buttons on the toolbar). if (whatHappened == HT_EVENT_NODE_DELETED_DATA || whatHappened == HT_EVENT_NODE_DELETED_NODATA) { // Delete the button if (HT_EVENT_NODE_DELETED_DATA == whatHappened) { // Destroy the toolbar button CRDFToolbarButton* pButton = (CRDFToolbarButton*)HT_GetNodeFEData(n); if (theToolbar->m_hWnd) theToolbar->RemoveButton(pButton); else theToolbar->DecrementButtonCount(); delete pButton; } } else if (whatHappened == HT_EVENT_NODE_ADDED) { theToolbar->AddHTButton(n); theToolbar->LayoutButtons(-1); } else if (whatHappened == HT_EVENT_NODE_VPROP_CHANGED) { CRDFToolbarButton* pButton = (CRDFToolbarButton*)HT_GetNodeFEData(n); pButton->SetText(HT_GetNodeName(n)); // Update our name. theToolbar->LayoutButtons(-1); } } } } } CRDFToolbar::CRDFToolbar(int nMaxButtons, int nToolbarStyle, int nPicturesAndTextHeight, int nPicturesHeight, int nTextHeight) : CNSToolbar2(nMaxButtons, nToolbarStyle, nPicturesAndTextHeight, nPicturesHeight, nTextHeight) { m_nNumberOfRows = 1; // Construct the notification struct used by HT HT_Notification ns = new HT_NotificationStruct; ns->notifyProc = ptNotifyProcedure; ns->data = this; // Construct the pane and give it our notification struct m_PersonalToolbarPane = HT_NewPersonalToolbarPane(ns); if (m_PersonalToolbarPane) HT_SetPaneFEData(m_PersonalToolbarPane, this); } CRDFToolbar* CRDFToolbar::CreateUserToolbar(CWnd* pParent) { // read in the maximum size we're allowing for personal toolbar items int32 nMaxToolbarButtonChars; int32 nMinToolbarButtonChars; if(PREF_GetIntPref("browser.personal_toolbar_button.max_chars", &nMaxToolbarButtonChars) == PREF_ERROR) m_nMaxToolbarButtonChars = 30; else m_nMaxToolbarButtonChars = CASTINT(nMaxToolbarButtonChars); if(PREF_GetIntPref("browser.personal_toolbar_button.min_chars", &nMinToolbarButtonChars) == PREF_ERROR) m_nMinToolbarButtonChars = 15; else m_nMinToolbarButtonChars = CASTINT(nMinToolbarButtonChars); CRDFToolbar* pToolbar = new CRDFToolbar(MAX_TOOLBAR_BUTTONS,theApp.m_pToolbarStyle, 43, 27, 27); if (pToolbar->Create(pParent)) { pToolbar->SetButtonsSameWidth(FALSE); // Top node is already open. Fill it in. pToolbar->FillInToolbar(); } return pToolbar; } CRDFToolbar::~CRDFToolbar() { if (m_PersonalToolbarPane) { HT_Pane oldPane = m_PersonalToolbarPane; m_PersonalToolbarPane = NULL; HT_DeletePane(oldPane); } } int CRDFToolbar::Create(CWnd *pParent) { int result = CNSToolbar2::Create(pParent); if(!result) return FALSE; m_DropTarget.Register(this); m_DropTarget.Toolbar(this); DragAcceptFiles(FALSE); return result; } void CRDFToolbar::FillInToolbar() { if (!m_PersonalToolbarPane) return; HT_View theView = HT_GetSelectedView(m_PersonalToolbarPane); if (theView == NULL) return; HT_Resource top = HT_TopNode(theView); HT_Cursor cursor = HT_NewCursor(top); if (cursor == NULL) return; HT_Resource item = NULL; while (item = HT_GetNextItem(cursor)) AddHTButton(item); HT_DeleteCursor(cursor); LayoutButtons(-1); } void CRDFToolbar::AddHTButton(HT_Resource item) { if (HT_IsSeparator(item)) return; CRDFToolbarButton* pButton = new CRDFToolbarButton; BOOKMARKITEM bookmark; XP_STRCPY(bookmark.szText, HT_GetNodeName(item)); XP_STRCPY(bookmark.szAnchor, HT_GetNodeURL(item)); CString csAmpersandString = FEU_EscapeAmpersand(CString(bookmark.szText)); pButton->Create(this, theApp.m_pToolbarStyle, CSize(60,42), CSize(85, 25), csAmpersandString, bookmark.szText, bookmark.szAnchor, CSize(23,17), m_nMaxToolbarButtonChars, m_nMinToolbarButtonChars, bookmark, item, (HT_IsContainer(item) ? TB_HAS_DRAGABLE_MENU | TB_HAS_IMMEDIATE_MENU : 0)); if(HT_IsContainer(item)) { CRDFToolbarButtonDropTarget *pDropTarget = new CRDFToolbarButtonDropTarget; pButton->SetDropTarget(pDropTarget); } HT_SetNodeFEData(item, pButton); AddButtonAtIndex(pButton); // Have to put the button in the array, since the toolbar base class depends on it. } int CRDFToolbar::GetHeight(void) { return m_nNumberOfRows * (LINKTOOLBARHEIGHT + SPACE_BETWEEN_ROWS) + SPACE_BETWEEN_ROWS; } void CRDFToolbar::SetMinimumRows(int rowWidth) { int rowCount = 1; int totalLine = 0; int rowSpace = rowWidth - RIGHT_TOOLBAR_MARGIN - LEFT_TOOLBAR_MARGIN; if (rowSpace <= 0) { SetRows(rowCount); return; } HT_Cursor cursor = HT_NewCursor(HT_TopNode(HT_GetSelectedView(m_PersonalToolbarPane))); if (!cursor) return; HT_Resource item; while (rowCount < MAX_TOOLBAR_ROWS && (item = HT_GetNextItem(cursor))) { // Get the current button CRDFToolbarButton* pButton = (CRDFToolbarButton*)(HT_GetNodeFEData(item)); if (!pButton) // Separator continue; CSize s = pButton->GetMinimalButtonSize(); int tempTotal = totalLine + s.cx; if (tempTotal > rowSpace) { rowCount++; totalLine = s.cx; } else totalLine = tempTotal; totalLine += SPACE_BETWEEN_BUTTONS; } HT_DeleteCursor(cursor); SetRows(rowCount); } void CRDFToolbar::ComputeLayoutInfo(CRDFToolbarButton* pButton, int numChars, int rowWidth, int& usedSpace) { CString originalText = HT_GetNodeName(pButton->GetNode()); int currCount = originalText.GetLength(); // Start off at the maximal string CString strTxt = originalText; if (currCount > numChars) { strTxt = originalText.Left(numChars-3) + "..."; } pButton->SetTextWithoutResize(strTxt); pButton->SetButtonSize(pButton->GetButtonSizeFromChars(strTxt, numChars)); // Determine how much additional padding we'll use to fill out a row if this button doesn't fit. int rowUsage = usedSpace % rowWidth; if (rowUsage == 0) rowUsage = rowWidth; int additionalPadding = rowWidth - rowUsage; int tempTotal = rowUsage + pButton->GetButtonSize().cx; // The button doesn't fit. Flesh out this row and start a new one. if (tempTotal > rowWidth) usedSpace += additionalPadding; // Add this button to the row. usedSpace += pButton->GetButtonSize().cx + SPACE_BETWEEN_BUTTONS; // Set this button's row information, so it knows which row it is currently residing on. int currentRow = usedSpace/rowWidth; if (usedSpace % rowWidth == 0) currentRow--; pButton->SetRow(currentRow); } void CRDFToolbar::LayoutButtons(int nIndex) { int width = m_nWidth; if (width <= 0) { CRect rect; GetParentFrame()->GetClientRect(&rect); width = rect.Width(); } int numButtonsAtMin = 0; int numButtonsAtMax = 0; int idealSpace = 0; // First quickly determine what the minimum # of rows we consume is. This is our allowed space. int oldRows = GetRows(); int rowWidth = width-RIGHT_TOOLBAR_MARGIN-LEFT_TOOLBAR_MARGIN; if (rowWidth <= 0 && m_nWidth > 0) rowWidth = m_nWidth - RIGHT_TOOLBAR_MARGIN - LEFT_TOOLBAR_MARGIN; SetMinimumRows(rowWidth); int newRows = GetRows(); int allowedSpace = rowWidth * GetRows(); // Toolbar width * numRows int usedSpace = 0; int numChars = 0; // Start off trying to fit the whole thing on the toolbar. int minChars = 0; HT_Cursor cursor = HT_NewCursor(HT_TopNode(HT_GetSelectedView(m_PersonalToolbarPane))); if (!cursor) return; HT_Resource item; while ((item = HT_GetNextItem(cursor))) { // Get the current button CRDFToolbarButton* pButton = (CRDFToolbarButton*)(HT_GetNodeFEData(item)); if (!pButton) continue; if (numChars == 0) { numChars = pButton->GetMaxTextCharacters(); minChars = pButton->GetMinTextCharacters(); } // See how much this num chars takes up ComputeLayoutInfo(pButton, numChars, rowWidth, usedSpace); } HT_DeleteCursor(cursor); while (usedSpace > allowedSpace && numChars > minChars) { usedSpace = 0; numChars--; // Let's see what we can fit. HT_Cursor cursor = HT_NewCursor(HT_TopNode(HT_GetSelectedView(m_PersonalToolbarPane))); if (!cursor) return; HT_Resource item; while ((item = HT_GetNextItem(cursor))) { // Get the current button CRDFToolbarButton* pButton = (CRDFToolbarButton*)(HT_GetNodeFEData(item)); if (!pButton) // Separator continue; // See how much this num chars takes up ComputeLayoutInfo(pButton, numChars, rowWidth, usedSpace); } HT_DeleteCursor(cursor); } // That's it. lay them out with this number of characters. int nStartX = LEFT_TOOLBAR_MARGIN; int nStartY = SPACE_BETWEEN_ROWS; int row = 0; CSize buttonSize; CString strTxt; cursor = HT_NewCursor(HT_TopNode(HT_GetSelectedView(m_PersonalToolbarPane))); if (!cursor) return; while ((item = HT_GetNextItem(cursor))) { // Get the current button CRDFToolbarButton* pButton = (CRDFToolbarButton*)(HT_GetNodeFEData(item)); if (!pButton) // Separator continue; buttonSize = pButton->GetButtonSize(); // The size we must be int tempTotal = nStartX + buttonSize.cx; if (tempTotal > (width - RIGHT_TOOLBAR_MARGIN)) { nStartX = LEFT_TOOLBAR_MARGIN; nStartY += LINKTOOLBARHEIGHT + SPACE_BETWEEN_ROWS; } pButton->MoveWindow(nStartX, nStartY, buttonSize.cx, buttonSize.cy); nStartX += buttonSize.cx + SPACE_BETWEEN_BUTTONS; } HT_DeleteCursor(cursor); //record the width of our toolbar //if (nStartY == SPACE_BETWEEN_ROWS && nStartX < (width - RIGHT_TOOLBAR_MARGIN)) // m_nWidth = nStartX; //else m_nWidth = width; if (oldRows != newRows) GetParentFrame()->RecalcLayout(); } void CRDFToolbar::WidthChanged(int animWidth) { CRect rect; GetParentFrame()->GetClientRect(&rect); int width = rect.Width() - animWidth; int numButtonsAtMin = 0; int numButtonsAtMax = 0; int idealSpace = 0; // First quickly determine what the minimum # of rows we consume is. This is our allowed space. int oldRows = GetRows(); int rowWidth = width-RIGHT_TOOLBAR_MARGIN-LEFT_TOOLBAR_MARGIN; if (rowWidth <= 0 && m_nWidth > 0) rowWidth = m_nWidth - RIGHT_TOOLBAR_MARGIN - LEFT_TOOLBAR_MARGIN; SetMinimumRows(rowWidth); int newRows = GetRows(); int allowedSpace = rowWidth * GetRows(); // Toolbar width * numRows int usedSpace = 0; int numChars = 0; // Start off trying to fit the whole thing on the toolbar. int minChars = 0; HT_Cursor cursor = HT_NewCursor(HT_TopNode(HT_GetSelectedView(m_PersonalToolbarPane))); if (!cursor) return; HT_Resource item; while ((item = HT_GetNextItem(cursor))) { // Get the current button CRDFToolbarButton* pButton = (CRDFToolbarButton*)(HT_GetNodeFEData(item)); if (!pButton) // Separator continue; if (numChars == 0) { numChars = pButton->GetMaxTextCharacters(); minChars = pButton->GetMinTextCharacters(); } // See how much this num chars takes up ComputeLayoutInfo(pButton, numChars, rowWidth, usedSpace); } HT_DeleteCursor(cursor); while (usedSpace > allowedSpace && numChars > minChars) { usedSpace = 0; numChars--; // Let's see what we can fit. HT_Cursor cursor = HT_NewCursor(HT_TopNode(HT_GetSelectedView(m_PersonalToolbarPane))); if (!cursor) return; HT_Resource item; while ((item = HT_GetNextItem(cursor))) { // Get the current button CRDFToolbarButton* pButton = (CRDFToolbarButton*)(HT_GetNodeFEData(item)); if (!pButton) continue; // See how much this num chars takes up ComputeLayoutInfo(pButton, numChars, rowWidth, usedSpace); } HT_DeleteCursor(cursor); } // That's it. lay them out with this number of characters. int nStartX = LEFT_TOOLBAR_MARGIN; int nStartY = SPACE_BETWEEN_ROWS; int row = 0; CSize buttonSize; CString strTxt; cursor = HT_NewCursor(HT_TopNode(HT_GetSelectedView(m_PersonalToolbarPane))); if (!cursor) return; while ((item = HT_GetNextItem(cursor))) { // Get the current button CRDFToolbarButton* pButton = (CRDFToolbarButton*)(HT_GetNodeFEData(item)); if (!pButton) continue; buttonSize = pButton->GetButtonSize(); // The size we must be int tempTotal = nStartX + buttonSize.cx; if (tempTotal > (width - RIGHT_TOOLBAR_MARGIN)) { nStartX = LEFT_TOOLBAR_MARGIN; nStartY += LINKTOOLBARHEIGHT + SPACE_BETWEEN_ROWS; } pButton->MoveWindow(nStartX, nStartY, buttonSize.cx, buttonSize.cy); nStartX += buttonSize.cx + SPACE_BETWEEN_BUTTONS; } HT_DeleteCursor(cursor); m_nWidth = width; if (oldRows != newRows) GetParentFrame()->RecalcLayout(); } /////////////////////////////////////////////////////////////////////////////////// // CRDFToolbar Messages /////////////////////////////////////////////////////////////////////////////////// BEGIN_MESSAGE_MAP(CRDFToolbar, CNSToolbar2) //{{AFX_MSG_MAP(CNSToolbar2) ON_WM_RBUTTONDOWN() //}}AFX_MSG_MAP END_MESSAGE_MAP() void CRDFToolbar::OnRButtonDown(UINT nFlags, CPoint point) { m_MenuCommandMap.Clear(); HT_View theView = HT_GetSelectedView(m_PersonalToolbarPane); HT_Cursor theCursor = HT_NewContextualMenuCursor(theView, PR_FALSE, PR_TRUE); CMenu menu; ClientToScreen(&point); if (menu.CreatePopupMenu() != 0 && theCursor != NULL) { // We have a cursor. Attempt to iterate HT_MenuCmd theCommand; while (HT_NextContextMenuItem(theCursor, &theCommand)) { char* menuName = HT_GetMenuCmdName(theCommand); if (theCommand == HT_CMD_SEPARATOR) menu.AppendMenu(MF_SEPARATOR); else { // Add the command to our command map CRDFMenuCommand* rdfCommand = new CRDFMenuCommand(menuName, theCommand); int index = m_MenuCommandMap.AddCommand(rdfCommand); menu.AppendMenu(MF_ENABLED, index+FIRST_HT_MENU_ID, menuName); } } HT_DeleteCursor(theCursor); menu.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this, NULL); menu.DestroyMenu(); } } BOOL CRDFToolbar::OnCommand( WPARAM wParam, LPARAM lParam ) { if (wParam >= FIRST_HT_MENU_ID && wParam <= LAST_HT_MENU_ID) { // A selection was made from the context menu. // Use the menu map to get the HT command value CRDFMenuCommand* theCommand = (CRDFMenuCommand*)(m_MenuCommandMap.GetCommand((int)wParam-FIRST_HT_MENU_ID)); if (theCommand) { HT_MenuCmd htCommand = theCommand->GetHTCommand(); HT_DoMenuCmd(m_PersonalToolbarPane, htCommand); } return TRUE; } return((BOOL)GetParentFrame()->SendMessage(WM_COMMAND, wParam, lParam)); }