/* -*- 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. */ // RDFLiner Implementation. Created by Dave Hyatt. #include "stdafx.h" #include "mainfrm.h" #include "hiddenfr.h" #include "xp_ncent.h" #include "rdf.h" #include "htrdf.h" #include "rdfliner.h" #include "pain.h" #include "shcut.h" #include "shcutdlg.h" #include "prefapi.h" #include "netsvw.h" #include "cxsave.h" #include "fegui.h" #include "nethelp.h" #include "time.h" #include "csid.h" #include "libi18n.h" CMapStringToPtr CHTFEData::m_LocalFileCache(40); CMapStringToPtr CHTFEData::m_CustomURLCache(20); extern "C" { #include "xpgetstr.h" extern int XP_BKMKS_LESS_THAN_ONE_HOUR_AGO; extern int XP_BKMKS_DAYS_AGO; extern int XP_BKMKS_HOURS_AGO; }; // Some tooltip stuff #define TIP_WAITING 1 #define TIP_SHOWING 2 #define TIP_SHOWN 3 #define TIP_HEARTBEAT 100 #define TIP_DELAY 250 // Focus/timer stuff for edit wnds #define IDT_EDITFOCUS 16412 #define IDT_SPRINGLOAD 16413 #define IDT_DRAGRECT 16414 #define EDIT_DELAY 500 #define SPRINGLOAD_DELAY 500 #define RDF_DRAG_HEARTBEAT 125 // Faster than COutliner's DRAG_HEARTBEAT // Click location stuff #define CLICKED_BACKGROUND 0 #define CLICKED_TRIGGER 1 #define CLICKED_LINE 2 #define CLICKED_BAR 3 // Used in painting #define COL_LEFT_MARGIN ((m_cxChar+1)/2) #define OUTLINE_TEXT_OFFSET 8 #define HTFE_USE_CUSTOM_IMAGE -1 #define HTFE_LOCAL_FILE -2 #define HT_NO_SORT -1 #define HT_SORT_ASCENDING 1 #define HT_SORT_DESCENDING 0 // The Nav Center vocab element extern "C" RDF_NCVocab gNavCenter; // Function to make a pretty date string #define SECONDS_PER_DAY 86400L void FormatDateTime( CTime &tmDate, CString &csFormatDate ) { // // Get locale info // static char cName[] = "intl" ; TCHAR szSepDate[2], szSepTime[2]; GetProfileString( cName, "sDate", "/", szSepDate, sizeof(szSepDate) ); GetProfileString( cName, "sTime", ":", szSepTime, sizeof(szSepTime) ); TCHAR szAM[9], szPM[9]; GetProfileString( cName, "s1159", "AM", szAM, sizeof(szAM) ); GetProfileString( cName, "s2359", "PM", szPM, sizeof(szPM) ); int iDate = GetProfileInt( cName, "iDate", 0 ); int iTime = GetProfileInt( cName, "iTime", 0 ); TCHAR szBuffer[64]; switch( iDate ) { default: case 0: // Month-Day-Year { wsprintf( szBuffer, "%d%s%d%s%d", tmDate.GetMonth(), szSepDate, tmDate.GetDay(), szSepDate, tmDate.GetYear() ); break; } case 1: // Day-Month-Year { wsprintf( szBuffer, "%d%s%d%s%d", tmDate.GetDay(), szSepDate, tmDate.GetMonth(), szSepDate, tmDate.GetYear() ); break; } case 2: // Year-Month-Day { wsprintf( szBuffer, "%d%s%d%s%d", tmDate.GetYear(), szSepDate, tmDate.GetMonth(), szSepDate, tmDate.GetDay() ); break; } } _tcscat( szBuffer, " " ); TCHAR *pszTime = &szBuffer[_tcslen( szBuffer )]; switch( iTime ) { default: case 0: // AM/PM 12-hour { BOOL bPM = FALSE; int iHour = tmDate.GetHour(); if( iHour > 11 ) { bPM = TRUE; iHour -= 12; } iHour = iHour ? iHour : 12; wsprintf( pszTime, "%d%s%.2d %s", iHour, szSepTime, tmDate.GetMinute(), (TCHAR *)(bPM ? szPM : szAM) ); break; } case 1: // 24-hour { wsprintf( pszTime, "%d%s%.2d", tmDate.GetHour(), szSepTime, tmDate.GetMinute() ); break; } } csFormatDate = (const char *)szBuffer; } void HTFE_MakePrettyDate(char* buffer, time_t lastVisited) { buffer[0] = 0; time_t today = XP_TIME(); int elapsed = today - lastVisited; if (elapsed < SECONDS_PER_DAY) { int32 hours = (elapsed + 1800L) / 3600L; if (hours < 1) { strcpy(buffer, XP_GetString(XP_BKMKS_LESS_THAN_ONE_HOUR_AGO)); } sprintf(buffer, XP_GetString(XP_BKMKS_HOURS_AGO), hours); } else if (elapsed < (SECONDS_PER_DAY * 31)) { sprintf(buffer, XP_GetString(XP_BKMKS_DAYS_AGO), (elapsed + (SECONDS_PER_DAY / 2)) / SECONDS_PER_DAY); } else { CString csFormatDate; CTime ctDate( lastVisited ); FormatDateTime( ctDate, csFormatDate ); _tcscpy( buffer, (const char *)csFormatDate ); } } BEGIN_MESSAGE_MAP(CRDFOutliner, COutliner) //{{AFX_MSG_MAP(CMainFrame) // NOTE - the ClassWizard will add and remove mapping macros here. // DO NOT EDIT what you see in these blocks of generated code ! ON_WM_PAINT() ON_WM_SETFOCUS() ON_WM_KILLFOCUS() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() ON_WM_MOUSEMOVE() ON_WM_RBUTTONDOWN() ON_WM_RBUTTONUP() ON_WM_CREATE() ON_WM_TIMER() ON_WM_SIZE() //}}AFX_MSG_MAP END_MESSAGE_MAP() CRDFOutliner::CRDFOutliner (CRDFOutlinerParent* theParent, HT_Pane thePane, HT_View theView) :COutliner(FALSE), m_pAncestor(NULL), m_Pane(thePane), m_View(theView), m_Parent(theParent), m_EditField(NULL), m_nSortType(HT_NO_SORT), m_nSortColumn(HT_NO_SORT), m_hEditTimer(0), m_hDragRectTimer(0), m_bNeedToClear(FALSE), m_nSelectedColumn(0), m_bDoubleClick(FALSE), m_Node(NULL), m_bDataSourceInWindow(FALSE), m_NavTitleBar(NULL), m_bIsPopup(FALSE), m_bTemporarilyRetainPopup(FALSE) { ApiApiPtr(api); m_pUnkUserImage = api->CreateClassInstance(APICLASS_IMAGEMAP,NULL,(APISIGNATURE)IDB_BOOKMARKS); if (m_pUnkUserImage) { m_pUnkUserImage->QueryInterface(IID_IImageMap,(LPVOID*)&m_pIUserImage); ASSERT(m_pIUserImage); if (!m_pIUserImage->GetResourceID()) m_pIUserImage->Initialize(IDB_BOOKMARKS,16,16); } } CRDFOutliner::~CRDFOutliner () { if (m_pUnkUserImage) { if (m_pIUserImage) m_pUnkUserImage->Release(); } delete []m_pAncestor; } int CRDFOutliner::OnCreate(LPCREATESTRUCT lpCreateStruct) { int iRetVal = COutliner::OnCreate(lpCreateStruct); DragAcceptFiles(FALSE); // RDF widget only take UTF8 SetCSID(CS_UTF8); return iRetVal; } void CRDFOutliner::OnSize( UINT nType, int cx, int cy ) { SqueezeColumns( -1, 0, FALSE ); m_iPaintLines = ( cy / m_itemHeight ) + 1; EnableScrollBars ( ); } void CRDFOutliner::HandleEvent(HT_Notification ns, HT_Resource n, HT_Event whatHappened) { if (whatHappened == HT_EVENT_VIEW_MODECHANGED) { ToggleModes(); } else if (whatHappened == HT_EVENT_NODE_OPENCLOSE_CHANGED) { FinishExpansion(HT_GetNodeIndex(m_View, n)); } else if (whatHappened == HT_EVENT_NODE_OPENCLOSE_CHANGING) { PRBool openState; HT_GetOpenState(n, &openState); if (openState) { // Node is closing. We need to iterate over our list of loading images and // if the node(s) that are observing the resource are children of this node, // we need to remove them from the observation list of the image. for (POSITION pos = loadingImagesList.GetHeadPosition(); pos != NULL; ) { // Enumerate over the list of loading images. CRDFImage* pImage = (CRDFImage*)loadingImagesList.GetNext(pos); // Figure out which of our resources are listening to this image. for (POSITION pos2 = pImage->resourceList.GetHeadPosition(); pos2 != NULL; ) { // Enumerate over the list and call remove listener on each image. CIconCallbackInfo* pInfo = (CIconCallbackInfo*)(pImage->resourceList.GetNext(pos2)); if (pInfo->pObject == this) { // We are currently observing this image. // Find out if the resource that is observing the image is a direct // descendant of the parent node that is closing. HT_Resource child; for (child = pInfo->pResource; child != NULL && child != n; child = HT_GetParent(child)); if (child == n) { // Do a removal. if (pos2 != NULL) // Not at the end { pImage->resourceList.GetPrev(pos2); if (pos2 == NULL) pos2 = pImage->resourceList.GetHeadPosition(); } pImage->RemoveListenerForSpecificResource(this, pInfo->pResource); } } } } } } else if (whatHappened == HT_EVENT_NODE_SELECTION_CHANGED) { int i = HT_GetNodeIndex(m_View, n); InvalidateLine(i); } else if (whatHappened == HT_EVENT_NODE_ADDED) { HT_Resource par = HT_GetParent(n); int toggle = -1; if (par != NULL) toggle = HT_GetNodeIndex(m_View, par); FinishExpansion(toggle); } else if (whatHappened == HT_EVENT_VIEW_SORTING_CHANGED) { if (m_Node) { int index = HT_GetNodeIndex(m_View, m_Node); m_iFocus = index; } Invalidate(); } else if (whatHappened == HT_EVENT_NODE_EDIT) { m_Node = n; m_iSelection = m_iFocus = HT_GetNodeIndex(m_View, n); m_nSelectedColumn = GetColumnAtPos(0); AddTextEdit(); } else if (whatHappened == HT_EVENT_NODE_DELETED_DATA || whatHappened == HT_EVENT_NODE_DELETED_NODATA) { m_iFocus = -1; } else if (whatHappened == HT_EVENT_VIEW_REFRESH) { SetTotalLines(HT_GetItemListCount(m_View)); Invalidate(); UpdateWindow(); } else if (whatHappened == HT_EVENT_NODE_VPROP_CHANGED) { // Invalidate a single line if (n) { int index = HT_GetNodeIndex(m_View, n); InvalidateLine(index); } } } void CRDFOutliner::InvalidateIconForResource(HT_Resource r) { int iLineNo = HT_GetNodeIndex(m_View, r); CRect rect, out; GetClientRect ( &rect ); RectFromLine ( iLineNo - m_iTopLine, rect, out ); int iImageWidth = GetIndentationWidth(); int indent = HT_GetItemIndentation(r); out.left = indent*iImageWidth; out.right = out.left + iImageWidth; InvalidateRect ( &out ); } void CRDFOutliner::InvalidateDragLine ( int iLineNo, BOOL useThirds, int dragFraction) { if (iLineNo == -1) return; CRect rect, out; GetClientRect ( &rect ); RectFromLine ( iLineNo - m_iTopLine, rect, out ); if (dragFraction == 1) { CRect topLine(out); topLine.bottom = out.top; InvalidateRect(&topLine); } if (dragFraction == 2) { if (useThirds) InvalidateRect(out); else dragFraction = 3; } if (dragFraction == 3) { CRect bottomLine(out); bottomLine.top = out.bottom-1; InvalidateRect ( &bottomLine ); } } LPCTSTR CRDFOutliner::GetColumnText ( UINT iColumn, void * pLineData ) { void* nodeData; time_t dateVal; struct tm* time; HT_Resource pEntry = (HT_Resource)pLineData; CRDFCommandMap& map = m_Parent->GetColumnCommandMap(); CRDFColumn* theColumn = (CRDFColumn*)(map.GetCommand(iColumn)); if (pEntry && HT_GetNodeData(pEntry, theColumn->GetToken(), theColumn->GetDataType(), &nodeData) && nodeData) { CString& buffer = theColumn->GetStorageBuffer(); char buf2[500]; // More than big enough for dates and ints switch (theColumn->GetDataType()) { case HT_COLUMN_DATE_STRING: if ((dateVal = (time_t)atol((char *)nodeData)) == 0) break; if ((time = localtime(&dateVal)) == NULL) break; HTFE_MakePrettyDate(buf2, dateVal); buffer = buf2; break; case HT_COLUMN_DATE_INT: if ((time = localtime((time_t *) &nodeData)) == NULL) break; HTFE_MakePrettyDate(buf2, (time_t)nodeData); buffer = buf2; break; case HT_COLUMN_INT: sprintf(buf2,"%d",(int)nodeData); buffer = buf2; break; case HT_COLUMN_STRING: buffer = (char*)nodeData; break; } return buffer; } return NULL; } void * CRDFOutliner::AcquireLineData ( int iLine ) { // Grab this resource if (GetTotalLines() <= iLine) return NULL; HT_Resource r = HT_GetNthItem(m_View, iLine); if (r != NULL) { int indent = HT_GetItemIndentation(r); BOOL hasPrev = HT_ItemHasBackwardSibling(r); BOOL hasNext = HT_ItemHasForwardSibling(r); if (m_bPaintingFirstObject || indent > m_nSizeOfAncestorArray) { OutlinerAncestorInfo* oldInfo = m_pAncestor; if (m_bPaintingFirstObject) { m_nSizeOfAncestorArray = indent; delete []oldInfo; oldInfo = NULL; } m_pAncestor = new OutlinerAncestorInfo[indent]; // Fill in the ancestor values. copyAncestorValues(r, m_nSizeOfAncestorArray, oldInfo, m_pAncestor); m_nSizeOfAncestorArray = indent; delete []oldInfo; } m_pAncestor[indent-1].has_next = hasNext; m_pAncestor[indent-1].has_prev = hasPrev; } return r; } void CRDFOutliner::ReleaseLineData ( void * pLineData ) { } void CRDFOutliner::GetTreeInfo( int iLine, uint32 * pFlags, int * iDepth, OutlinerAncestorInfo ** pAncestor ) { HT_Resource r = HT_GetNthItem(m_View, iLine); if (r == NULL) return; if (pFlags) *pFlags = (uint32)HT_IsContainer(r); if (iDepth) *iDepth = HT_GetItemIndentation(r)-1; if (pAncestor) *pAncestor = m_pAncestor; } void CRDFOutliner::copyAncestorValues(HT_Resource r, int numItems, OutlinerAncestorInfo* oldInfo, OutlinerAncestorInfo* newInfo) { if (oldInfo != NULL) { for (int i = 0; i < numItems; i++) { newInfo[i].has_next = oldInfo[i].has_next; newInfo[i].has_prev = oldInfo[i].has_prev; } } else { // Have to acquire ALL the data. HT_Resource currNode = r; for (int i = numItems-1; i >= 0; i--) { newInfo[i].has_next = HT_ItemHasForwardSibling(currNode); newInfo[i].has_prev = HT_ItemHasBackwardSibling(currNode); currNode = HT_GetParent(currNode); } } } BOOL CRDFOutliner::IsSelected(int iLine) { HT_Resource r = HT_GetNthItem(m_View, iLine); return (r != NULL) && (HT_IsSelected(r)); } HFONT CRDFOutliner::GetLineFont ( void * pLineData ) { // Will need to hack this for aliases/shortcuts? (italics!) /*HT_Resource r = (HT_Resource)pLineData; char* url = HT_GetNodeURL(r); if (url && !IsLocalFile(url)) return m_hItalFont; */ return m_hRegFont; } int CRDFOutliner::TranslateIcon ( void * pData ) { HT_Resource data = (HT_Resource)pData; char* pURL = HT_GetNodeSmallIconURL(data); //TRACE("%s\n", pURL); if (strncmp("icon", pURL, 4) == 0) { // Icon URL if ((strcmp("icon/small:folder/closed", pURL) == 0) || (strcmp("icon/small:folder,history/closed", pURL) == 0)) return IDX_BOOKMARKCLOSED; if ((strcmp("icon/small:folder/open", pURL) == 0) || (strcmp("icon/small:folder,history/open", pURL) == 0)) return IDX_BOOKMARKOPEN; if (strcmp("icon/small:url", pURL) == 0) return IDX_BOOKMARK; if ((strcmp("icon/small:file/local", pURL) == 0) || (strcmp("icon/small:folder/local,closed", pURL) == 0) || (strcmp("icon/small:folder/local,open", pURL) == 0)) return HTFE_LOCAL_FILE; // Catchall code for unknown ICON urls if (HT_IsContainer(data)) { if (HT_IsContainerOpen(data)) return IDX_BOOKMARKOPEN; else return IDX_BOOKMARKCLOSED; } return IDX_BOOKMARK; } // Handle the arbitrary URL case return HTFE_USE_CUSTOM_IMAGE; } int CRDFOutliner::TranslateIconFolder( void *pData ) { HT_Resource data = (HT_Resource)pData; if (data) { if (HT_IsContainer(data)) { if (HT_IsContainerOpen(data)) { return OUTLINER_OPENFOLDER; } else { return OUTLINER_CLOSEDFOLDER; } } } return OUTLINER_ITEM; } void CRDFOutliner::LoadComplete(HT_Resource pResource) { if (pResource == NULL) // Background image loaded. Invalidate(); else InvalidateIconForResource(pResource); // Individual line had an image load. } // Functions used to draw custom images (either local file system icons or arbitrary image URLs) HICON DrawLocalFileIcon(HT_Resource r, int left, int top, HDC hDC) { char* pLocalName = NULL; HICON hIcon = FetchLocalFileIcon(r); if (hIcon) { // Now we draw this bad boy. DrawIconEx(hDC, left, top, hIcon, 0, 0, 0, NULL, DI_NORMAL); } return hIcon; } CRDFImage* DrawArbitraryURL(HT_Resource r, int left, int top, int imageWidth, int imageHeight, HDC hDC, COLORREF bkColor, CCustomImageObject* pObject, BOOL isToolbarIcon, HT_IconType state) { CRDFImage* pImage = FetchCustomIcon(r, pObject, isToolbarIcon, state); return DrawRDFImage(pImage, left, top, imageWidth, imageHeight, hDC, bkColor); } CRDFImage* DrawRDFImage(CRDFImage* pImage, int left, int top, int imageWidth, int imageHeight, HDC hDC, COLORREF bkColor) { if (pImage && pImage->FrameLoaded()) { // Now we draw this bad boy. if (pImage->m_BadImage) { // display broken icon. HDC tempDC = ::CreateCompatibleDC(hDC); HBITMAP hOldBmp = (HBITMAP)::SelectObject(tempDC, CRDFImage::m_hBadImageBitmap); ::StretchBlt(hDC, left, top, imageWidth, imageHeight, tempDC, 0, 0, imageWidth, imageHeight, SRCCOPY); ::SelectObject(tempDC, hOldBmp); ::DeleteDC(tempDC); } else if (pImage->bits ) { // Center the image. long width = pImage->bmpInfo->bmiHeader.biWidth; long height = pImage->bmpInfo->bmiHeader.biHeight; int xoffset = (imageWidth-width)/2; int yoffset = (imageHeight-height)/2; if (xoffset < 0) xoffset = 0; if (yoffset < 0) yoffset = 0; if (width > imageWidth) width = imageWidth; if (height > imageHeight) height = imageHeight; HPALETTE hPal = WFE_GetUIPalette(NULL); HPALETTE hOldPal = ::SelectPalette(hDC, hPal, TRUE); ::RealizePalette(hDC); if (pImage->maskbits) { WFE_StretchDIBitsWithMask(hDC, TRUE, NULL, left+xoffset, top+xoffset, width, height, 0, 0, width, height, pImage->bits, pImage->bmpInfo, pImage->maskbits, FALSE, 0); } else { ::StretchDIBits(hDC, left+xoffset, top+xoffset, width, height, 0, 0, width, height, pImage->bits, pImage->bmpInfo, DIB_RGB_COLORS, SRCCOPY); } ::SelectPalette(hDC, hOldPal, TRUE); } } return pImage; } BOOL IsLocalFile(const char* pURL) { return strncmp(pURL, "file:", 5) == 0; } BOOL IsExecutableURL(const char* pURL) { char* pLocalName = NULL; if (!XP_ConvertUrlToLocalFile(pURL, &pLocalName)) return FALSE; pLocalName = NET_UnEscape(pLocalName); // Do a FindExecutable. If the filenames match, we win. char execName[_MAX_PATH]; if (FEU_FindExecutable(pLocalName, execName, FALSE)) { // Well, there's at least SOMETHING. // See if it matches us. char answerString[_MAX_PATH]; strcpy(answerString, pLocalName); char execString[_MAX_PATH]; strcpy(execString, execName); #ifdef _WIN32 GetShortPathName(pLocalName, answerString, _MAX_PATH); GetShortPathName(execName, execString, _MAX_PATH); #endif // _WIN32 if (!stricmp(answerString, execString)) return TRUE; } if (pLocalName) XP_FREE(pLocalName); return FALSE; } // The expansion handler int CRDFOutliner::ToggleExpansion (int iLine) { PRBool openp; HT_Resource pEntry = HT_GetNthItem(m_View, iLine); if (pEntry && HT_IsContainer(pEntry)) { HT_GetOpenState(pEntry, &openp); HT_SetOpenState(pEntry, (PRBool)(!openp)); } return 0; } HICON FetchLocalFileIcon(HT_Resource r) { HICON hIcon = NULL; CString hashString(HT_GetNodeURL(r)); if (hashString.GetLength() < 12) // Hack. It's a disk volume. { // Hash disk drives based on URL. } else if (HT_IsContainer(r)) { // We're a directory. if (HT_IsContainerOpen(r)) hashString = "open folder"; else hashString = "closed folder"; } else { // We're a file. int index = hashString.ReverseFind('.'); if (index == -1) hashString = "no extension"; else hashString = hashString.Right(hashString.GetLength() - index); } void* hashPtr; char* pLocalName = NULL; if (CHTFEData::m_LocalFileCache.Lookup(hashString, hashPtr)) { // We found an icon in the icon cache. hIcon = (HICON)hashPtr; } else { XP_ConvertUrlToLocalFile(HT_GetNodeURL(r), &pLocalName); pLocalName = NET_UnEscape(pLocalName); SHFILEINFO shInfo; shInfo.hIcon = NULL; if (HT_IsContainer(r) && HT_IsContainerOpen(r)) SHGetFileInfo(pLocalName, 0, &shInfo, sizeof(shInfo), SHGFI_OPENICON | SHGFI_ICON | SHGFI_SMALLICON); else SHGetFileInfo(pLocalName, 0, &shInfo, sizeof(shInfo), SHGFI_ICON | SHGFI_SMALLICON); if(shInfo.hIcon) { hIcon = shInfo.hIcon; // Add to the local file cache. CHTFEData::m_LocalFileCache.SetAt(hashString, (void*)hIcon); } if (pLocalName) XP_FREE(pLocalName); } return hIcon; } CRDFImage* FetchCustomIcon(HT_Resource r, CCustomImageObject* imageObject, BOOL isToolbarIcon, HT_IconType state) { CRDFImage* pImage = NULL; CString hashString = HT_GetIconURL(r, isToolbarIcon, state); if (strncmp("icon/large:workspace", hashString, 20) == 0) { char name[8]; int ret = sscanf(hashString, "icon/large:workspace,%s", name); if (ret != 0) hashString = CString("about:") + name + ".gif"; } else if (strncmp("icon/large:folder", hashString, 17) == 0) { hashString = "about:personal.gif"; } pImage = imageObject->LookupImage(hashString, r); return pImage; } IconType DetermineIconType(HT_Resource pNode, BOOL isToolbar, HT_IconType state) { IconType returnValue; if (pNode != NULL) { char* pURL = HT_GetIconURL(pNode, isToolbar, state); //TRACE("%s\n", pURL); if (strncmp("icon", pURL, 4) != 0) { // Time to load a custom image. returnValue = ARBITRARY_URL; } else if ((strncmp("icon/large:workspace", pURL, 20) == 0) || (strncmp("icon/large:folder", pURL, 17) == 0)) { returnValue = ARBITRARY_URL; } else if (IsLocalFile(HT_GetNodeURL(pNode))) { returnValue = LOCAL_FILE; } else returnValue = BUILTIN_BITMAP; } else returnValue = BUILTIN_BITMAP; return returnValue; } // The callback for finishing the expansion void CRDFOutliner::FinishExpansion(int toggleIndex) { int iCount = GetTotalLines(); int newCount = HT_GetItemListCount(m_View); SetTotalLines(newCount); // Update the outliner's visible lines int iDelta = newCount - iCount; int iSel = GetFocusLine(); if (iSel > toggleIndex) { if (iDelta > 0) { iSel += iDelta; } else { if (iSel < (toggleIndex - iDelta)) { iSel = toggleIndex; } else { iSel += iDelta; } } if (iSel != GetFocusLine()) { m_iFocus = m_iSelection = iSel; InvalidateLine(m_iFocus); } } if ( iDelta > 0 ) { iDelta = iDelta > m_iPaintLines - 2 ? m_iPaintLines - 2 : iDelta; if (!m_bDataSourceInWindow) // Springloading folders go haywire if we shift lines around, so don't do it EnsureVisible( toggleIndex + iDelta ); } Invalidate(); } void CRDFOutliner::SelectItem(int iSel,int mode,UINT flags) { int oldColumn = GetSelectedColumn(); if (m_iColHit == -1) return; UINT command = m_pColumn[ m_iColHit ]->iCommand; RemoveTextEdit(); m_Node = HT_GetNthItem(m_View, iSel); if (!m_Node) { HT_SetSelectionAll(m_View, (PRBool)FALSE); if (mode != OUTLINER_RBUTTONDOWN) return; m_Node = HT_TopNode(m_View); iSel = -1; } switch (mode) { case OUTLINER_RETURN: case OUTLINER_LBUTTONDBLCLK: OnSelDblClk(iSel); m_bDoubleClick = TRUE; if (m_hEditTimer) { KillTimer(m_hEditTimer); m_hEditTimer = 0; } break; case OUTLINER_LBUTTONUP: if (m_bNeedToClear) { HT_SetSelection(m_Node); if (m_bNeedToEdit && !m_bDoubleClick && m_bUseInlineEditing) { CRDFCommandMap& map = m_Parent->GetColumnCommandMap(); CRDFColumn* theColumn = (CRDFColumn*)(map.GetCommand(m_nSelectedColumn)); BOOL isEditable = HT_IsNodeDataEditable(m_Node, theColumn->GetToken(), theColumn->GetDataType()); // Get down.... get down... time for a column edit. if (isEditable) m_hEditTimer = SetTimer(IDT_EDITFOCUS, EDIT_DELAY, NULL); } } m_bNeedToClear = FALSE; m_bNeedToEdit = FALSE; m_bDoubleClick = FALSE; if (m_bUseSingleClick) OnSelDblClk(iSel); break; case OUTLINER_LBUTTONDOWN: case OUTLINER_KEYDOWN: case OUTLINER_SET: m_iFocus = iSel; m_bNeedToClear = FALSE; m_bNeedToEdit = FALSE; SetSelectedColumn((int)command); if (flags & MK_CONTROL) { // Causes a selection toggle. HT_ToggleSelection(m_Node); } else if (flags & MK_SHIFT) { // A range of items is being selected. HT_Resource node = HT_GetNthItem(m_View, m_iSelection); if (node != NULL) { HT_SetSelectionRange(node, m_Node); } } else { m_iSelection = iSel; if (!IsSelected(m_iFocus)) { HT_SetSelection(m_Node); //if (!HT_IsContainer(m_Node) && !HT_IsSeparator(m_Node) && IsDocked()) // DisplayURL(); For now do double-click behavior } else { m_bNeedToClear = TRUE; if (oldColumn == m_nSelectedColumn) m_bNeedToEdit = TRUE; } } break; case OUTLINER_RBUTTONDOWN: m_iFocus = iSel; SetSelectedColumn((int)command); m_iSelection = iSel; if (m_iFocus >= 0 && !IsSelected(m_iFocus)) { HT_SetSelection(m_Node); } break; default: break; } } BOOL CRDFOutliner::DeleteItem(int iSel) { HT_DoMenuCmd(m_Pane, HT_CMD_CUT); return TRUE; } BOOL CRDFOutliner::IsDocked() { CGenericFrame* theFrame = (CGenericFrame*)FEU_GetLastActiveFrame(); if (theFrame == NULL) return FALSE; return theFrame->IsChild(this); } void CRDFOutliner::ToggleModes() { void* data; // Whether or not to show column headers HT_GetTemplateData(HT_TopNode(m_View), gNavCenter->showColumnHeaders, HT_COLUMN_STRING, &data); BOOL show = TRUE; if (data) { char* answer = (char*)data; show = stricmp(answer, "No"); } CRDFOutlinerParent* pParent = (CRDFOutlinerParent*)GetParent(); pParent->EnableHeaders(show); // Need to invalidate the title strip and figure out exactly how tall it is. CRDFContentView* pView = (CRDFContentView*)(GetParent()->GetParent()); CRect parentRect; pParent->GetClientRect(&parentRect); int titleHeight = pView->GetTitleBar()->GetHeightBasedOnProperties(); pView->GetTitleBar()->MoveWindow(CRect(0, 0, parentRect.Width(), titleHeight)); pParent->MoveWindow(CRect(0, titleHeight, parentRect.Width(), parentRect.Height() - titleHeight)); } void CRDFOutliner::OnSelDblClk(int iLine) { if (m_Node) { if (HT_IsContainer(m_Node)) { ToggleExpansion(iLine); } else if (!HT_IsSeparator(m_Node))// && !IsDocked()) For now always do double-click behavior { DisplayURL(); if (IsPopup()) { // Destroy the entire tree. CFrameWnd* pFrameWnd = GetParentFrame(); if (pFrameWnd->IsKindOf(RUNTIME_CLASS(CNSNavFrame))) ((CNSNavFrame*)pFrameWnd)->DeleteNavCenter(); } } } } void CRDFOutliner::SetHTView(HT_View v) { m_Pane = HT_GetPane(v); m_View = v; m_iSelection = m_iFocus = -1; int newCount = HT_GetItemListCount(m_View); SetTotalLines(newCount); // Update the outliner's visible lines m_iTopLine = 0; } void CRDFOutliner::DisplayURL() { char* url = HT_GetNodeURL(m_Node); // Hacking the window target (Added by Dave on 7/12/98) CAbstractCX * pCX = FEU_GetLastActiveFrameContext(); //Check for whether we need new browser window. if (pCX == NULL) { // Fake "open in new window". HT_DoMenuCmd(m_Pane, HT_CMD_OPEN_NEW_WIN); return; } // Let HT handle some URLs. if (HT_Launch(m_Node, pCX->GetContext())) return; // Shell execute all local file URLs. (Disable for bookmarks until we have a concrete plan.) if (IsLocalFile(url) && HT_GetParent(m_Node) != NULL && IsLocalFile(HT_GetNodeURL(HT_GetParent(m_Node)))) { char* pLocalName = NULL; XP_ConvertUrlToLocalFile(url, &pLocalName); pLocalName = NET_UnEscape(pLocalName); SHELLEXECUTEINFO sei; // Use ShellExecuteEx to launch sei.cbSize = sizeof(sei); sei.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_NOCLOSEPROCESS; sei.hwnd = NULL; sei.lpVerb = NULL; // default to Open sei.lpFile = pLocalName; sei.lpParameters = NULL; sei.lpDirectory = NULL; sei.nShow = SW_SHOW; ShellExecuteEx(&sei); int uSpawn = (UINT)sei.hInstApp; if(uSpawn <= 32) { char szMsg[80]; switch(uSpawn) { case 0: case 8: sprintf(szMsg, szLoadString(IDS_WINEXEC_0_8)); break; case 2: case 3: sprintf(szMsg, szLoadString(IDS_WINEXEC_2_3)); break; case 10: case 11: case 12: case 13: case 14: case 15: sprintf(szMsg, szLoadString(IDS_WINEXEC_10_THRU_15)); break; case 16: sprintf(szMsg, szLoadString(IDS_WINEXEC_16)); break; case 21: sprintf(szMsg, szLoadString(IDS_WINEXEC_21)); break; default: sprintf(szMsg, szLoadString(IDS_WINEXEC_XX), uSpawn); break; } CString s; if (s.LoadString( IDS_BOOKMARK_ADDRESSPROPERTIES )) { ::MessageBox(GetParentFrame()->m_hWnd, szMsg, s, MB_OK | MB_APPLMODAL); } } if (pLocalName) XP_FREE(pLocalName); } else if (m_WindowTarget == "") pCX->NormalGetUrl((LPTSTR) url, "rdftree"); // Do a normal fetch. else pCX->NormalGetUrl((LPTSTR) url, "rdftree", (char*)(const char*)m_WindowTarget); } BOOL CRDFOutliner::TestRowCol(POINT point, int &iRow, int &iCol) { RECT rcClient; GetClientRect(&rcClient); BOOL answer = TRUE; if (::PtInRect(&rcClient, point)) { void *pLineData = NULL; int iSel = point.y / m_itemHeight; int iNewSel = m_iTopLine + iSel; if ( ( pLineData = AcquireLineData ( iNewSel ) ) != NULL ) { ReleaseLineData( pLineData ); iRow = iNewSel; } else answer = FALSE; int i, offset; int y = iSel * m_itemHeight; for ( i = 0, offset = 0; i < m_iVisColumns; i++ ) { CRect rect ( offset, y, offset + m_pColumn[ i ]->iCol, y + m_itemHeight ); if ( rect.PtInRect(point) ) { iCol = i; m_rcHit = rect; return answer; } offset += m_pColumn[ i ]->iCol; } } return FALSE; } int CRDFOutliner::DetermineClickLocation(CPoint point) { // TestRowCol returns FALSE if the row clicked on contains no data. We must have clicked on the background // in this case. int iRow, iCol; if ( !TestRowCol( point, iRow, iCol ) ) return CLICKED_BACKGROUND; // We clicked on a row/column with data. Update our member variables to reflect our hit. m_iRowHit = iRow; m_iColHit = iCol; // Get the text rectangle corresponding to the hit column. CRect textRect = GetColumnRect(iRow, (int)(m_pColumn[iCol]->iCommand)); // Double-check and make sure we have line data. (We should, but let's be safe.) void * pLineData; if ( ( pLineData = AcquireLineData ( iRow ) ) == NULL) return CLICKED_BACKGROUND; int iDepth; GetTreeInfo ( iRow, NULL, &iDepth, NULL ); HT_Resource r = (HT_Resource)pLineData; ReleaseLineData ( pLineData ); int iTriggerSize = 9; int iBarWidth = iTriggerSize / 2 + 1; // 5 pixels out of the 9. // If the user clicked on the image column, they might have struck the trigger. Check for this. if ( m_pColumn[ iCol ]->iCommand == m_idImageCol ) { int iImageWidth = GetIndentationWidth(); RECT rcToggle = m_rcHit; rcToggle.left += iDepth * iImageWidth; rcToggle.right = rcToggle.left + iImageWidth; rcToggle.top += (iImageWidth - iTriggerSize) / 2 + 2; // Account for the pixel of padding rcToggle.bottom = rcToggle.top + iTriggerSize; // If the data is a container and if the point is inside the toggle rect, the user clicked the // trigger. if ( ::PtInRect( &rcToggle, point ) && HT_IsContainer(r)) return CLICKED_TRIGGER; // The user may have clicked on a bar. if (m_bHasPipes && point.x > iImageWidth && point.x < rcToggle.right) // No bars on the outermost level { int area = point.x % iImageWidth; // Determine where within the particular level the click occurred int left = (iImageWidth - iBarWidth) / 2; int right = left + iBarWidth; if (area >= left && area <= right) return CLICKED_BAR; } // If the user clicked to the left of the trigger on a container, then treat as a background click. // If the user clicked where the trigger would have been (or to the left of the trigger) on a non- // container, then treat that as a background click also. if ((point.x < rcToggle.left && HT_IsContainer(r)) || (point.x < rcToggle.right && !HT_IsContainer(r))) return CLICKED_BACKGROUND; } // See if the user clicked on the column text. const char* text = GetColumnText(m_pColumn[ iCol ]->iCommand, r); if (!text) return CLICKED_BACKGROUND; // Column has no text. User has to have clicked on the background. // All this code just determines our text rectangle. CClientDC dc(this); CRect bgRect; dc.SelectObject( GetLineFont( r ) ); UINT dwDTFormat = DT_NOCLIP | DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER; switch (m_pColumn[ iCol ]->alignment) { case AlignCenter: dwDTFormat |= DT_CENTER; break; case AlignRight: dwDTFormat |= DT_RIGHT; break; case AlignLeft: default: dwDTFormat |= DT_LEFT; } CIntlWin::DrawText(CS_UTF8, dc, (char*)text, -1, &bgRect, DT_CALCRECT | dwDTFormat); int w = bgRect.Width() + 2*COL_LEFT_MARGIN; if (w > textRect.Width()) w = textRect.Width(); bgRect.left = textRect.left; bgRect.top = textRect.top; bgRect.right = bgRect.left + w; bgRect.bottom = textRect.bottom; if ( m_pColumn[ iCol ]->iCommand == m_idImageCol ) bgRect.left -= (m_pIUserImage->GetImageWidth() + OUTLINE_TEXT_OFFSET); // Now that we've set up the rect, see if the user clicked in it. If they didn't, it's a background // click. if (!bgRect.PtInRect(point)) return CLICKED_BACKGROUND; // User jumped through all our hoops. Must have clicked on some actual data. return CLICKED_LINE; } void CRDFOutliner::OnLButtonDown ( UINT nFlags, CPoint point ) { // Reset drag rect info m_bCheckForDragRect = FALSE; m_LastDragRect = CRect(0,0,0,0); m_nRectYDisplacement = 0; Default(); TipHide(); SetFocus(); m_ptHit = point; m_iRowHit = -1; m_iColHit = -1; int clickResult = DetermineClickLocation(point); if (clickResult == CLICKED_TRIGGER) DoToggleExpansion(m_iRowHit); else if (clickResult == CLICKED_BAR) { int clickDepth = m_ptHit.x / GetIndentationWidth(); HT_Resource r = (HT_Resource)AcquireLineData(m_iRowHit); if (r) { for (HT_Resource curr = r; curr && HT_GetItemIndentation(curr) > clickDepth; curr = HT_GetParent(curr)); if (curr) HT_SetOpenState(curr, PR_FALSE); } } else if (clickResult == CLICKED_LINE) { if ( ColumnCommand( m_pColumn[ m_iColHit ]->iCommand, m_iRowHit) ) return; SetCapture(); SelectItem( m_iRowHit, OUTLINER_LBUTTONDOWN, nFlags ); } else { // user clicked on the background m_bCheckForDragRect = TRUE; SetCapture(); m_iFocus = -1; if (m_iColHit != -1) { SetSelectedColumn(m_pColumn[ m_iColHit ]->iCommand); } HT_SetSelectionAll(m_View, (PRBool)FALSE); } } void CRDFOutliner::OnLButtonUp(UINT nFlags, CPoint point) { if (GetCapture() == this) { ReleaseCapture(); if (m_LastDragRect != CRect(0,0,0,0)) { // Dragging happened CClientDC dc(this); EraseDragRect(&dc, m_LastDragRect); if (m_hDragRectTimer) { KillTimer(m_hDragRectTimer); m_hDragRectTimer = 0; } } else SelectItem( m_iSelection, OUTLINER_LBUTTONUP, nFlags ); } } void CRDFOutliner::OnRButtonDown ( UINT nFlags, CPoint point ) { // Update our column hit, since we draw selected columns. m_iRowHit = -1; m_iColHit = -1; int clickResult = DetermineClickLocation(point); if (clickResult == CLICKED_LINE) { // user clicked on the item. We will go ahead and select. SelectItem( m_iRowHit, OUTLINER_RBUTTONDOWN, nFlags ); } else { // user clicked on the background... deselect everything. m_iFocus = -1; HT_SetSelectionAll(m_View, (PRBool)FALSE); } /* int iRow, iCol; if ( TestRowCol( point, iRow, iCol ) ){ HT_Resource pEntry = HT_GetNthItem(m_View, iRow); CExportRDF exportDlg; if (exportDlg.DoModal() == IDOK) { FILE* mcfStr; mcfStr = fopen(exportDlg.m_csAns, "w"); outputMCFTree(RDF_GetNavCenterDB(), stdPrint, mcfStr, HT_GetRDFResource(pEntry)); fclose(mcfStr); } } */ } void CRDFOutliner::OnRButtonUp( UINT nFlags, CPoint point ) { m_ptHit = point; int iSel = m_iTopLine + (point.y / m_itemHeight); int clickResult = DetermineClickLocation(point); PropertyMenu( iSel, clickResult ); } void CRDFOutliner::DragRectScroll( BOOL bBackwards ) { int oldLine = m_iTopLine; OnVScroll(bBackwards ? SB_LINEUP : SB_LINEDOWN, 0, 0); m_nRectYDisplacement += (oldLine - m_iTopLine)*m_itemHeight; if (m_nRectYDisplacement != 0) { OnMouseMove(0, m_MovePoint); } } CRect CRDFOutliner::ConstructDragRect(const CPoint& pt1, const CPoint& pt2) { int left = pt1.x < pt2.x ? pt1.x : pt2.x; int right = pt1.x > pt2.x ? pt1.x : pt2.x; int top = pt1.y < pt2.y ? pt1.y : pt2.y; int bottom = pt1.y > pt2.y ? pt1.y : pt2.y; return CRect(left, top, right, bottom); } void CRDFOutliner::EraseDragRect(CDC* pDC, CRect rect) { #ifdef XP_WIN32 CRgn rgnLast, rgnOutside, rgnInside; // set up regions and rects for drag rect with border of size (1,1) rgnLast.CreateRectRgn(0, 0, 0, 0); rgnOutside.CreateRectRgnIndirect(&rect); CRect rect2 = rect; rect.InflateRect(-1, -1); rect.IntersectRect(rect, rect2); rgnInside.CreateRectRgnIndirect(&rect); rgnLast.CombineRgn(&rgnOutside, &rgnInside, RGN_XOR); // Do the erase pDC->SelectClipRgn(&rgnLast); pDC->GetClipBox(&rect); CBrush* pBrushLast = CDC::GetHalftoneBrush(); CBrush* pBrushOld = pDC->SelectObject(pBrushLast); pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATINVERT); pDC->SelectObject(pBrushOld); pDC->SelectClipRgn(NULL); #endif } void CRDFOutliner::OnMouseMove(UINT nFlags, CPoint point) { if (GetCapture() == this) { #ifdef XP_WIN32 if (m_bCheckForDragRect) { CRect rect; GetClientRect(&rect); // We're dragging a rectangle, baby. if (point.x < 0) // HACK so hit test works point.x = 0; if (point.y < 0) point.y = 0; if (point.y > rect.bottom) point.y = rect.bottom; m_MovePoint = point; if ( point.y < m_itemHeight ) { m_hDragRectTimer = SetTimer(IDT_DRAGRECT, GetDragHeartbeat(), NULL); } else if ( point.y > (rect.bottom - m_itemHeight) ) { m_hDragRectTimer = SetTimer(IDT_DRAGRECT, GetDragHeartbeat(), NULL); } else if (m_hDragRectTimer) { KillTimer(m_hDragRectTimer); m_hDragRectTimer = 0; } CClientDC dc(this); CRect newRect = ConstructDragRect(m_ptHit, point); // Determine the new selection state if (m_LastDragRect == CRect(0,0,0,0)) dc.DrawDragRect(&newRect, CSize(1,1), NULL, CSize(1,1)); else { // Displace the rects to account for scrolling m_LastDragRect.OffsetRect(0, m_nRectYDisplacement); newRect.OffsetRect(0, m_nRectYDisplacement); if (m_nRectYDisplacement > 0) newRect.top += m_nRectYDisplacement; else newRect.bottom -= m_nRectYDisplacement; // Reset the displacement for future scroll events m_nRectYDisplacement = 0; // Potential to add selection. CPoint testPoint1 = m_LastDragRect.TopLeft(); CPoint testPoint2 = newRect.TopLeft(); if (m_LastDragRect.bottom != newRect.bottom) { testPoint1 = CPoint(m_LastDragRect.left, m_LastDragRect.bottom); testPoint2 = CPoint(newRect.left, newRect.bottom); } int iRow = -1; int iCol = -1; int otherRow = -1; int otherCol = -1; TestRowCol(testPoint1, iRow, iCol); TestRowCol(testPoint2, otherRow, otherCol); // Select the item we're on. Always do this. HT_Resource r = HT_GetNthItem(m_View, iRow); if (r) HT_SetSelectedState(r, PR_TRUE); // Both over selections. if (iRow != otherRow) { // Erase the old drag rect EraseDragRect(&dc, m_LastDragRect); UpdateWindow(); // Add or remove selection... int start; int end; BOOL select; if (iRow == -1) iRow = otherRow+1; else if (otherRow == -1) otherRow = iRow+1; if (m_LastDragRect.bottom < newRect.bottom) { start = iRow+1; end = otherRow+1; select = TRUE; } else if (m_LastDragRect.bottom > newRect.bottom) { start = otherRow+1; end = iRow+1; select = FALSE; } else if (m_LastDragRect.top > newRect.top) { start = otherRow; end = iRow; select = TRUE; } else if (m_LastDragRect.top < newRect.top) { start = iRow; end = otherRow; select = FALSE; } // Going from start to end, performing selection for (int i = start; i < end; i++) { HT_Resource r = HT_GetNthItem(m_View, i); if (r) HT_SetSelectedState(r, (PRBool)select); } UpdateWindow(); // Draw the new rect dc.DrawDragRect(&newRect, CSize(1,1), NULL, CSize(1,1)); } else dc.DrawDragRect(&newRect, CSize(1,1), &m_LastDragRect, CSize(1,1)); } m_LastDragRect = newRect; } else #endif // XP_WIN32 // See if the mouse has moved far enough to start // a drag operation if ((abs(point.x - m_ptHit.x) > 3) || (abs(point.y - m_ptHit.y) > 3)) { // release the mouse capture ReleaseCapture(); InitiateDragDrop(); m_bClearOnRelease = FALSE; m_bSelectOnRelease = FALSE; SelectItem( m_iSelection, OUTLINER_LBUTTONUP, nFlags ); } } if (m_iTipState != TIP_SHOWING) m_iTipState = TIP_WAITING; HandleMouseMove( point ); } void CRDFOutliner::PropertyMenu(int iLine, UINT flags) { // Grab the resource BOOL backgroundCommands = (flags == CLICKED_BACKGROUND); CMenu popup; if (popup.CreatePopupMenu() != 0) { // We have a node and a menu. Fetch those commands. // Remove the elements from the last property menu we pulled up. m_MenuCommandMap.Clear(); HT_Cursor theCursor = HT_NewContextualMenuCursor(m_View, (PRBool)FALSE, (PRBool)backgroundCommands); 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) popup.AppendMenu(MF_SEPARATOR); else { // Add the command to our command map CRDFMenuCommand* rdfCommand = new CRDFMenuCommand(menuName, theCommand); int index = m_MenuCommandMap.AddCommand(rdfCommand); popup.AppendMenu(MF_ENABLED, index+FIRST_HT_MENU_ID, menuName); } } HT_DeleteCursor(theCursor); } // Track the popup now. POINT pt = m_ptHit; ClientToScreen(&pt); popup.TrackPopupMenu( TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, this, NULL ); // Cleanup popup.DestroyMenu(); } } BOOL CRDFOutliner::OnCommand(UINT wParam, LONG 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_Pane, htCommand); } } return TRUE; } void CRDFOutliner::OnSetFocus ( CWnd * pOldWnd ) { // Update the context's stored RDF Info. Hack for the back end. Needs to go away eventually. theApp.m_pRDFCX->TrackRDFWindow(this); SetTemporaryRetainOnPopup(FALSE); Default(); if (m_iSelection >= 0) for (int i =0; i < (m_iTopLine+m_iPaintLines); i++) if (IsSelected(i)) InvalidateLine(i); FocusCheck(pOldWnd, TRUE); } void CRDFOutliner::OnKillFocus ( CWnd * pNewWnd ) { CWnd::OnKillFocus ( pNewWnd ); if (m_iSelection >= 0) for (int i =0; i < (m_iTopLine+m_iPaintLines); i++) if (IsSelected(i)) InvalidateLine(i); ((COutlinerParent*)GetParent())->UpdateFocusFrame(); FocusCheck(pNewWnd, FALSE); } void CRDFOutliner::FocusCheck(CWnd* pWnd, BOOL gotFocus) { if (m_NavTitleBar) { if (gotFocus) m_NavTitleBar->NotifyFocus(TRUE); else { CFrameWnd* pFrameWnd = GetParentFrame(); if (pFrameWnd && !pFrameWnd->IsChild(pWnd)) { // Invalidate for a redraw m_NavTitleBar->NotifyFocus(FALSE); if (IsPopup() && !ShouldRetainPopup()) { // Destroy the window. if (pFrameWnd->IsKindOf(RUNTIME_CLASS(CNSNavFrame))) ((CNSNavFrame*)pFrameWnd)->DeleteNavCenter(); } } } } } COLORREF Darken(COLORREF r) { COLORREF ref = GetSysColor(COLOR_WINDOW); float x = GetRValue(ref); float y = GetGValue(ref); float z = GetBValue(ref); x = 0.75f*(x+1); y = 0.75f*(y+1); z = 0.75f*(z+1); BYTE newR = (BYTE)(int)x; BYTE newG = (BYTE)(int)y; BYTE newB = (BYTE)(int)z; return RGB(newR, newG, newB); } COLORREF Brighten(COLORREF r) { COLORREF ref = GetSysColor(COLOR_WINDOW); float x = GetRValue(ref); float y = GetGValue(ref); float z = GetBValue(ref); x = x + 0.25f*(256 - x); y = y + 0.25f*(256 - y); z = z + 0.25f*(256 - z); if (x > 255.0f) x = 255.0f; if (y > 255.0f) y = 255.0f; if (z > 255.0f) z = 255.0f; BYTE newR = (BYTE)(int)x; BYTE newG = (BYTE)(int)y; BYTE newB = (BYTE)(int)z; return RGB(newR, newG, newB); } void ResolveToPaletteColor(COLORREF& color, HPALETTE hPal) { int index = ::GetNearestPaletteIndex(hPal, color); PALETTEENTRY palEntry; ::GetPaletteEntries(hPal, index, 1, &palEntry); unsigned uRed = palEntry.peRed; unsigned uGreen = palEntry.peGreen; unsigned uBlue = palEntry.peBlue; color = RGB(uRed, uGreen, uBlue); } void CRDFOutliner::OnPaint() { m_bPaintingFirstObject = TRUE; RECT rcClient; GetClientRect(&rcClient); CPaintDC pdc ( this ); if (m_View == NULL) return; // Read in all the properties HT_Resource top = HT_TopNode(m_View); void* data; PRBool foundData = FALSE; // Options for management mode style by default. m_ForegroundColor = RGB(0,0,0); m_BackgroundColor = RGB(240,240,240); m_SortBackgroundColor = RGB(224,224,224); m_SortForegroundColor = RGB(0,0,0); m_bHasPipes = TRUE; m_bDrawDividers = TRUE; m_bUseSingleClick = FALSE; m_bUseInlineEditing = TRUE; // Foreground color HT_GetTemplateData(top, gNavCenter->viewFGColor, HT_COLUMN_STRING, &data); if (data) WFE_ParseColor((char*)data, &m_ForegroundColor); // background color HT_GetTemplateData(top, gNavCenter->viewBGColor, HT_COLUMN_STRING, &data); if (data) WFE_ParseColor((char*)data, &m_BackgroundColor); HT_GetTemplateData(top, gNavCenter->showTreeConnections, HT_COLUMN_STRING, &data); if (data) { CString answer((char*)data); if (answer.GetLength() > 0 && (answer.GetAt(0) == 'n' || answer.GetAt(0) == 'N')) m_bHasPipes = FALSE; } // Sort foreground color HT_GetTemplateData(top, gNavCenter->sortColumnFGColor, HT_COLUMN_STRING, &data); if (data) WFE_ParseColor((char*)data, &m_SortForegroundColor); // Sort background color HT_GetTemplateData(top, gNavCenter->sortColumnBGColor, HT_COLUMN_STRING, &data); if (data) WFE_ParseColor((char*)data, &m_SortBackgroundColor); // Compute the shadow/highlight colors for sorting and for normal modes. Compute3DColors(m_SortBackgroundColor, m_SortHighlightColor, m_SortShadowColor); Compute3DColors(m_BackgroundColor, m_HighlightColor, m_ShadowColor); // Selection foreground color HT_GetTemplateData(top, gNavCenter->selectionFGColor, HT_COLUMN_STRING, &data); if (data) WFE_ParseColor((char*)data, &m_SelectionForegroundColor); else m_SelectionForegroundColor = RGB(255,255,255); // Selection background color HT_GetTemplateData(top, gNavCenter->selectionBGColor, HT_COLUMN_STRING, &data); if (data) WFE_ParseColor((char*)data, &m_SelectionBackgroundColor); else m_SelectionBackgroundColor = RGB(0,0,128); // Background image URL m_BackgroundImageURL = ""; HT_GetTemplateData(top, gNavCenter->viewBGURL, HT_COLUMN_STRING, &data); if (data) m_BackgroundImageURL = (char*)data; m_pBackgroundImage = NULL; // Clear out the BG image. // Divider color m_DividerColor = RGB(255,255,255); HT_GetTemplateData(top, gNavCenter->dividerColor, HT_COLUMN_STRING, &data); if (data) WFE_ParseColor((char*)data, &m_DividerColor); HT_GetTemplateData(top, gNavCenter->showDivider, HT_COLUMN_STRING, &data); if (data) { CString answer((char*)data); if (answer.GetLength() > 0 && (answer.GetAt(0) == 'n' || answer.GetAt(0) == 'N')) m_bDrawDividers = FALSE; } HT_GetTemplateData(top, gNavCenter->useInlineEditing, HT_COLUMN_STRING, &data); if (data) { CString answer((char*)data); if (answer.GetLength() > 0 && (answer.GetAt(0) == 'n' || answer.GetAt(0) == 'N')) m_bUseInlineEditing = FALSE; } HT_GetTemplateData(top, gNavCenter->useSingleClick, HT_COLUMN_STRING, &data); if (data) { CString answer((char*)data); if (answer.GetLength() > 0 && (answer.GetAt(0) == 'Y' || answer.GetAt(0) == 'y')) m_bUseSingleClick = TRUE; } HPALETTE pOldPalette = NULL; if (sysInfo.m_iBitsPerPixel < 16 && (::GetDeviceCaps(pdc.m_hDC, RASTERCAPS) & RC_PALETTE)) { // Use the palette, since we have less than 16 bits per pixel and are // using a palette-based device. HPALETTE hPalette = WFE_GetUIPalette(GetParentFrame()); ::SelectPalette(pdc.m_hDC, hPalette, FALSE); // Find the nearest match in our palette for our colors. ResolveToPaletteColor(m_BackgroundColor, hPalette); ResolveToPaletteColor(m_ForegroundColor, hPalette); ResolveToPaletteColor(m_SelectionForegroundColor, hPalette); ResolveToPaletteColor(m_SelectionBackgroundColor, hPalette); ResolveToPaletteColor(m_SortBackgroundColor, hPalette); ResolveToPaletteColor(m_SortForegroundColor, hPalette); ResolveToPaletteColor(m_DividerColor, hPalette); } HBRUSH hRegBrush = (HBRUSH) ::CreateSolidBrush(m_BackgroundColor); HPEN hRegPen = (HPEN)::CreatePen( PS_SOLID, 0, m_BackgroundColor); HBRUSH hHighBrush = ::CreateSolidBrush( m_SelectionBackgroundColor ); HPEN hHighPen = ::CreatePen( PS_SOLID, 0, m_SelectionBackgroundColor ); HBRUSH hOldBrush = (HBRUSH) pdc.SelectObject ( hRegBrush ); HPEN hOldPen = (HPEN) pdc.SelectObject ( hRegPen ); COLORREF cOldText = pdc.SetTextColor ( m_ForegroundColor ); int previousBkMode = pdc.SetBkMode(TRANSPARENT); // Construct a precise line invalidation rect. int start = pdc.m_ps.rcPaint.top / m_itemHeight; int end = pdc.m_ps.rcPaint.bottom / m_itemHeight + 1; CRect clientRect; GetClientRect(&clientRect); CRect bgFillRect; bgFillRect.left = 0; bgFillRect.right = clientRect.Width(); bgFillRect.top = m_itemHeight*start; bgFillRect.bottom = m_itemHeight*end; if (m_BackgroundImageURL != "") { // There's a background that needs to be drawn. m_pBackgroundImage = LookupImage(m_BackgroundImageURL, NULL); } if (m_pBackgroundImage && m_pBackgroundImage->FrameSuccessfullyLoaded()) { int imageHeight = m_pBackgroundImage->bmpInfo->bmiHeader.biHeight; int ySrcOffset = (bgFillRect.top + m_iTopLine*m_itemHeight) % imageHeight; PaintBackground(pdc, bgFillRect, m_pBackgroundImage, 0, ySrcOffset); } else { ::FillRect(pdc, bgFillRect, hRegBrush); } int i; for (i = start; i <= end; i++) { int index = i + m_iTopLine; PaintLine ( i, pdc.m_hDC, &pdc.m_ps.rcPaint, hHighBrush, hHighPen ); if (m_bPaintingFirstObject) m_bPaintingFirstObject = FALSE; } pdc.SetTextColor ( cOldText ); pdc.SetBkMode(previousBkMode); pdc.SelectObject ( hOldPen ); pdc.SelectObject ( hOldBrush ); if (sysInfo.m_iBitsPerPixel < 16 && (::GetDeviceCaps(pdc.m_hDC, RASTERCAPS) & RC_PALETTE)) { ::SelectPalette(pdc.m_hDC, pOldPalette, FALSE); } VERIFY(DeleteObject( hRegBrush )); VERIFY(DeleteObject( hRegPen )); VERIFY(DeleteObject( hHighBrush )); VERIFY(DeleteObject( hHighPen )); } void DrawBGSubimage(CRDFImage* pImage, HDC hDC, int xSrcOffset, int ySrcOffset, int xDstOffset, int yDstOffset, int width, int height) { if (pImage->bits) { HPALETTE hPal = WFE_GetUIPalette(NULL); HPALETTE hOldPal = ::SelectPalette(hDC, hPal, TRUE); ::RealizePalette(hDC); int oldMode = ::SetMapMode(hDC, MM_TEXT); if (pImage->maskbits) { WFE_StretchDIBitsWithMask(hDC, TRUE, NULL, xDstOffset, yDstOffset, width, height, xSrcOffset, ySrcOffset, width, height, pImage->bits, pImage->bmpInfo, pImage->maskbits, FALSE, RGB(0,0,0)); } else { ::StretchDIBits(hDC, xDstOffset, yDstOffset, width, height, xSrcOffset, ySrcOffset, width, height, pImage->bits, pImage->bmpInfo, DIB_RGB_COLORS, SRCCOPY); } ::SetMapMode(hDC, oldMode); ::SelectPalette(hDC, hOldPal, TRUE); } } #define LIGHT_GRAY RGB(192, 192, 192) #define DARK_GRAY RGB(128, 128, 128) #define WHITE RGB(255, 255, 255) #define BLACK RGB(0, 0, 0) void GetSystem3DColors(COLORREF rgbBackground, COLORREF& rgbLightColor, COLORREF& rgbDarkColor) { #ifdef XP_WIN32 if (sysInfo.IsWin4_32()) { // These are Windows 95 only rgbLightColor = ::GetSysColor(COLOR_3DLIGHT); rgbDarkColor = ::GetSysColor(COLOR_3DSHADOW); } else { rgbLightColor = LIGHT_GRAY; rgbDarkColor = ::GetSysColor(COLOR_BTNSHADOW); } #else rgbLightColor = LIGHT_GRAY; rgbDarkColor = ::GetSysColor(COLOR_BTNSHADOW); #endif // We need to make sure that both colors are visible against // the background if (rgbLightColor == rgbBackground) rgbLightColor = rgbBackground == LIGHT_GRAY ? WHITE : LIGHT_GRAY; if (rgbDarkColor == rgbBackground) rgbDarkColor = rgbBackground == DARK_GRAY ? BLACK : DARK_GRAY; } // Constants for calculating Highlight (TS = "TopShadow") and // shadow (BS = "BottomShadow") values relative to background // Taken from UNIX version -- Eric Bina's Visual.c // // Bias brightness calculation by standard color-sensitivity values // (Percents -- UNIX used floats, but we don't need to) // #define RED_LUMINOSITY 30 #define GREEN_LUMINOSITY 59 #define BLUE_LUMINOSITY 11 // Percent effect of intensity, light, and luminosity & on brightness, #define INTENSITY_FACTOR 25 #define LIGHT_FACTOR 0 #define LUMINOSITY_FACTOR 75 // LITE color model percent to interpolate RGB towards black for BS, TS #define COLOR_LITE_BS_FACTOR 45 #define COLOR_LITE_TS_FACTOR 70 // DARK color model - percent to interpolate RGB towards white for BS, TS #define COLOR_DARK_BS_FACTOR 30 #define COLOR_DARK_TS_FACTOR 50 #define MAX_COLOR 255 #define COLOR_DARK_THRESHOLD 51 #define COLOR_LIGHT_THRESHOLD 204 void DrawArrow(HDC hDC, COLORREF arrowColor, int type, CRect rect, BOOL enabled) { HPEN hArrowPen = ::CreatePen(PS_SOLID, 1, arrowColor); HPEN hOldPen = (HPEN)::SelectObject(hDC, hArrowPen); int size = (type == UP_ARROW || type == DOWN_ARROW) ? rect.Width() : rect.Height(); int endPoint = (type == UP_ARROW || type == DOWN_ARROW) ? rect.left : rect.top; if (type == UP_ARROW) { for (int j = 0; j < 4; j++) { int yPos = rect.top + (rect.Height()/2) - 2 + j; int x1 = rect.left + (rect.Width()/2) - j; int x2 = x1 + 2*j; ::MoveToEx(hDC, x1, yPos,NULL); ::LineTo(hDC, x2+1, yPos); } } else if (type == DOWN_ARROW) { // Draw a down arrow. for (int j = 0; j < 4; j++) { int yPos = rect.top + (rect.Height()/2) + 1 - j; int x1 = rect.left + (rect.Width()/2) - j; int x2 = x1 + 2*j; ::MoveToEx(hDC,x1,yPos,NULL); ::LineTo(hDC,x2+1,yPos); } } else if (type == LEFT_ARROW) { for (int j = 0; j < 4; j++) { int xPos = rect.left + (rect.Width()/2) - 2 + j; int y1 = rect.top + (rect.Height()/2) - j; int y2 = y1 + 2*j; ::MoveToEx(hDC,xPos,y1,NULL); ::LineTo(hDC,xPos,y2+1); } } else if (type == RIGHT_ARROW) { // Draw a down arrow. for (int j = 0; j < 4; j++) { int xPos = rect.left + (rect.Width()/2) + 1 - j; int y1 = rect.top + (rect.Height()/2) - j; int y2 = y1 + 2*j; ::MoveToEx(hDC,xPos,y1,NULL); ::LineTo(hDC,xPos,y2+1); } } ::SelectObject(hDC, hOldPen); VERIFY(::DeleteObject(hArrowPen)); } void Compute3DColors(COLORREF rgbColor, COLORREF &rgbLight, COLORREF &rgbDark) { unsigned uRed, uGreen, uBlue; unsigned uRedBack = GetRValue(rgbColor); unsigned uGreenBack = GetGValue(rgbColor); unsigned uBlueBack = GetBValue(rgbColor); unsigned intensity = (uRedBack + uGreenBack + uBlueBack) / 3; unsigned luminosity = ((RED_LUMINOSITY * uRedBack)/ 100) + ((GREEN_LUMINOSITY * uGreenBack)/ 100) + ((BLUE_LUMINOSITY * uBlueBack)/ 100); unsigned backgroundBrightness = ((intensity * INTENSITY_FACTOR) + (luminosity * LUMINOSITY_FACTOR)) / 100; unsigned f; if (backgroundBrightness < COLOR_DARK_THRESHOLD) { // Dark Background - interpolate 30% toward black uRed = uRedBack - (COLOR_DARK_BS_FACTOR * uRedBack / 100); uGreen = uGreenBack - (COLOR_DARK_BS_FACTOR * uGreenBack / 100); uBlue = uBlueBack - (COLOR_DARK_BS_FACTOR * uBlueBack / 100); rgbDark = RGB(uRed, uGreen, uBlue); // This interpolotes to 50% toward white uRed = uRedBack + (COLOR_DARK_TS_FACTOR * (MAX_COLOR - uRedBack) / 100); uGreen = uGreenBack + (COLOR_DARK_TS_FACTOR * (MAX_COLOR - uGreenBack) / 100); uBlue = uBlueBack + (COLOR_DARK_TS_FACTOR * (MAX_COLOR - uBlueBack) / 100); } else if (backgroundBrightness > COLOR_LIGHT_THRESHOLD) { // Interpolate 45% toward black uRed = uRedBack - (COLOR_LITE_BS_FACTOR * uRedBack / 100); uGreen = uGreenBack - (COLOR_LITE_BS_FACTOR * uGreenBack / 100); uBlue = uBlueBack - (COLOR_LITE_BS_FACTOR * uBlueBack / 100); rgbDark = RGB(uRed, uGreen, uBlue); // Original algorithm (from X source: visual.c) used: // uRed = uRedBack - (COLOR_LITE_TS_FACTOR * uRedBack / 100), // where FACTOR is 20%, but that makes no sense! // I think the intention was large interpolation toward white, // so use max of "medium" range (70%) for smooth continuity across threshhold uRed = uRedBack + (COLOR_LITE_TS_FACTOR * (MAX_COLOR - uRedBack) / 100); uGreen = uGreenBack + (COLOR_LITE_TS_FACTOR * (MAX_COLOR - uGreenBack) / 100); uBlue = uBlueBack + (COLOR_LITE_TS_FACTOR * (MAX_COLOR - uBlueBack) / 100); } else { // Medium Background f = COLOR_DARK_BS_FACTOR + (backgroundBrightness * ( COLOR_LITE_BS_FACTOR - COLOR_DARK_BS_FACTOR ) / MAX_COLOR); uRed = uRedBack - (f * uRedBack / 100); uGreen = uGreenBack - (f * uGreenBack / 100); uBlue = uBlueBack - (f * uBlueBack / 100); rgbDark = RGB(uRed, uGreen, uBlue); f = COLOR_DARK_TS_FACTOR + (backgroundBrightness * ( COLOR_LITE_TS_FACTOR - COLOR_DARK_TS_FACTOR ) / MAX_COLOR); uRed = uRedBack + (f * (MAX_COLOR - uRedBack) / 100); uGreen = uGreenBack + (f * (MAX_COLOR - uGreenBack) / 100); uBlue = uBlueBack + (f * (MAX_COLOR - uBlueBack) / 100); } // Safety check for upper limit uRed = min(MAX_COLOR, uRed); uGreen = min(MAX_COLOR, uGreen); uBlue = min(MAX_COLOR, uBlue); rgbLight = RGB(uRed, uGreen, uBlue); // Special case white backgrounds and black backgrounds if (rgbLight == rgbColor && (uRedBack == MAX_COLOR && uGreenBack == MAX_COLOR && uBlueBack == MAX_COLOR)) { // For a white separator use medium gray colors. rgbLight = RGB(192,192,192); } else if (rgbDark == rgbColor && rgbColor == 0) { // Use a dark gray color. rgbDark = RGB(64,64,64); } // If either of these colors is the same as the background color // then use the system 3D element colors instead if (rgbLight == rgbColor || rgbDark == rgbColor) { GetSystem3DColors(rgbColor, rgbLight, rgbDark); } } void PaintBackground(HDC hdc, CRect rect, CRDFImage* pImage, int xSrcOffset, int ySrcOffset) { int totalWidth = rect.Width(); int totalHeight = rect.Height(); if (!pImage->bits) return; int imageWidth = pImage->bmpInfo->bmiHeader.biWidth; int imageHeight = pImage->bmpInfo->bmiHeader.biHeight; // Ok, complicated math time. int xDstOffset = rect.left; int yDstOffset = rect.top; if (ySrcOffset == -1) // Assume we don't have a scrolled offset in the view we're drawing into. ySrcOffset = rect.top % imageHeight; if (xSrcOffset == -1) // Assume we don't have a scrolled offset in the view we're drawing into. xSrcOffset = rect.left % imageWidth; int xRemainder = imageWidth - xSrcOffset; int yRemainder = imageHeight - ySrcOffset; int xSize = xRemainder > totalWidth ? totalWidth : xRemainder; int ySize = yRemainder > totalHeight ? totalHeight : yRemainder; while (yDstOffset < rect.bottom) { // Tile vertically while (xDstOffset < rect.right) { int ySrc = ySrcOffset; if (imageHeight != ySize) ySrc = imageHeight - ySize - ySrcOffset; DrawBGSubimage(pImage, hdc, xSrcOffset, ySrc, xDstOffset, yDstOffset, xSize, ySize); xSrcOffset = 0; xDstOffset += xSize; xSize = (xDstOffset + imageWidth) > rect.right ? imageWidth - (xDstOffset + imageWidth) + rect.right : imageWidth; } xDstOffset = rect.left; xSize = (xDstOffset + imageWidth) > rect.right ? rect.right - xDstOffset : imageWidth; ySrcOffset = 0; yDstOffset += ySize; ySize = (yDstOffset + imageHeight) > rect.bottom ? rect.bottom - yDstOffset : imageHeight; } } void CRDFOutliner::PaintLine ( int iLineNo, HDC hdc, LPRECT lpPaintRect, HBRUSH hHighlightBrush, HPEN hHighlightPen ) { void * pLineData; int iImageWidth = GetIndentationWidth(); CRect WinRect; GetClientRect(&WinRect); int y = m_itemHeight * iLineNo; int iColumn, offset; CRect rectColumn, rectInter; rectColumn.top = y; rectColumn.bottom = y + m_itemHeight; if ( !( pLineData = AcquireLineData( iLineNo + m_iTopLine )) ) { // We're drawing a blank line. if (ViewerHasFocus() && HasFocus(iLineNo + m_iTopLine)) { CRect internalRect(rectColumn); internalRect.top += 1; // Move in by a pixel. internalRect.bottom -= 2; // Move in by a pixel + the divider line. internalRect.left = WinRect.left; internalRect.right = WinRect.right; DrawFocusRect ( hdc, &internalRect ); } // Draw the column rect for ( int iColumn = offset = 0; iColumn < m_iVisColumns; iColumn++ ) { rectColumn.left = offset; rectColumn.right = offset + m_pColumn[ iColumn ]->iCol; if (iColumn == GetSortColumn()) { // Draw the sort rect. HBRUSH hSortBrush = (HBRUSH)::CreateSolidBrush(m_SortBackgroundColor); ::FillRect(hdc, &rectColumn, hSortBrush); VERIFY(DeleteObject(hSortBrush)); } offset += m_pColumn[ iColumn ]->iCol; } return; } // Draw the divider if (m_bDrawDividers) { CDC* pDC = CDC::FromHandle(hdc); HPEN hDividerPen = ::CreatePen(PS_SOLID, 1, m_DividerColor); HPEN pOldPen = (HPEN)::SelectObject(hdc, hDividerPen); pDC->MoveTo(WinRect.left, rectColumn.bottom-1); pDC->LineTo(WinRect.right, rectColumn.bottom-1); ::SelectObject(hdc, pOldPen); VERIFY(::DeleteObject(hDividerPen)); } HFONT hOldFont =(HFONT) ::SelectObject ( hdc, GetLineFont ( pLineData ) ); for ( iColumn = offset = 0; iColumn < m_iVisColumns; iColumn++ ) { rectColumn.left = offset; rectColumn.right = offset + m_pColumn[ iColumn ]->iCol; if ( rectInter.IntersectRect ( &rectColumn, lpPaintRect ) ) { HBRUSH hSortBrush; if (iColumn == GetSortColumn()) { hSortBrush = (HBRUSH)::CreateSolidBrush(m_SortBackgroundColor); CRect tempRect(rectColumn); if (m_bDrawDividers) tempRect.bottom--; ::FillRect(hdc, &tempRect, hSortBrush); VERIFY(DeleteObject(hSortBrush)); } if ( m_pColumn[ iColumn ]->iCommand == m_idImageCol ) { rectColumn.left = DrawPipes ( iLineNo, iColumn, offset, hdc, pLineData ); } PaintColumn ( iLineNo, iColumn, rectColumn, hdc, pLineData, hHighlightBrush, hHighlightPen ); } offset += m_pColumn[ iColumn ]->iCol; } rectColumn.left = offset; rectColumn.right = WinRect.right; if (!(m_pBackgroundImage && m_pBackgroundImage->FrameSuccessfullyLoaded())) { if (m_bDrawDividers) rectColumn.bottom--; // Handle the divider ::FillRect(hdc, &rectColumn, (HBRUSH) GetCurrentObject(hdc, OBJ_BRUSH)); PaintColumn ( iLineNo, iColumn, rectColumn, hdc, pLineData, hHighlightBrush, hHighlightPen ); } rectColumn.left = WinRect.left; rectColumn.right = WinRect.right; // if we are dragging we and we don't highlight we need to draw the drag line if(m_iDragSelection == m_iTopLine + iLineNo && !HighlightIfDragging() && GetSortColumn() == -1 && m_iCurrentDropAction != DROPEFFECT_NONE) PaintDragLine(hdc, rectColumn); ::SelectObject ( hdc, hOldFont ); ReleaseLineData ( pLineData ); } void CRDFOutliner::PaintColumn(int iLineNo, int iColumn, LPRECT lpColumnRect, HDC hdc, void * pLineData, HBRUSH hHighlightBrush, HPEN hHighlightPen) { if (iColumn < m_iVisColumns) { HT_Resource theNode = (HT_Resource)pLineData; const char* lpsz = GetColumnText (m_pColumn[ iColumn ]->iCommand,pLineData); if (theNode && HT_IsSeparator(theNode)) { // Alter the column text name. lpsz = NULL; } if ( !RenderData( m_pColumn[iColumn]->iCommand, CRect(lpColumnRect), *CDC::FromHandle( hdc ), lpsz) ) { BOOL hasFocus = FALSE; CRect WinRect; GetClientRect(&WinRect); if (theNode && HT_IsSeparator(theNode) && lpColumnRect->right != WinRect.right) { // Draw the horizontal line. CPen separatorHighlightPen; CPen separatorShadowPen; if (iColumn == GetSortColumn()) { separatorHighlightPen.CreatePen(PS_SOLID, 1, m_SortHighlightColor); separatorShadowPen.CreatePen(PS_SOLID, 1, m_SortShadowColor); } else { separatorHighlightPen.CreatePen(PS_SOLID, 1, m_HighlightColor); separatorShadowPen.CreatePen(PS_SOLID, 1, m_ShadowColor); } //HPEN sepPen = (HPEN)separatorPen.GetSafeHandle(); //HPEN usePen = IsSelected(iLineNo) ? hHighlightPen : sepPen; HPEN pOldPen = (HPEN)(::SelectObject(hdc, (HPEN)separatorShadowPen.GetSafeHandle())); ::MoveToEx(hdc, lpColumnRect->left, lpColumnRect->top+m_itemHeight/2, NULL); ::LineTo(hdc, lpColumnRect->right, lpColumnRect->top+m_itemHeight/2); ::SelectObject(hdc, (HPEN)separatorHighlightPen.GetSafeHandle()); ::MoveToEx(hdc, lpColumnRect->left, lpColumnRect->top+m_itemHeight/2+1, NULL); ::LineTo(hdc, lpColumnRect->right, lpColumnRect->top+m_itemHeight/2+1); ::SelectObject(hdc, pOldPen); } if (lpsz) { if ((IsSelected(iLineNo + m_iTopLine) || ((m_iDragSelection == m_iTopLine + iLineNo) && HighlightIfDragging())) && IsSelectedColumn(iColumn)) { hasFocus = HasFocus(iLineNo + m_iTopLine); if (ViewerHasFocus()) { HBRUSH pOldBrush = (HBRUSH)(::SelectObject ( hdc, hHighlightBrush )); HPEN pOldPen = (HPEN)(::SelectObject ( hdc, hHighlightPen )); COLORREF cOldText = ::SetTextColor ( hdc, m_SelectionForegroundColor ); DrawColumn ( hdc, lpColumnRect, lpsz, m_pColumn[ iColumn ]->cropping, m_pColumn[ iColumn ]->alignment, hHighlightBrush, hasFocus ); ::SelectObject(hdc, pOldBrush); ::SelectObject(hdc, pOldPen); ::SetTextColor ( hdc, cOldText ); } else DrawColumn ( hdc, lpColumnRect, lpsz, m_pColumn[ iColumn ]->cropping, m_pColumn[ iColumn ]->alignment, hHighlightBrush, hasFocus ); } else DrawColumn ( hdc, lpColumnRect, lpsz, m_pColumn[ iColumn ]->cropping, m_pColumn[ iColumn ]->alignment); } } } } void CRDFOutliner::DrawColumn(HDC hdc, LPRECT lpColumnRect, LPCTSTR lpszString, CropType_t cropping, AlignType_t alignment, HBRUSH theBrush, BOOL hasFocus) { if (!(lpColumnRect->right - lpColumnRect->left)) return; ASSERT(lpszString); int iLength = _tcslen(lpszString); if (!iLength) return; UINT dwDTFormat = DT_NOCLIP | DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER; switch (alignment) { case AlignCenter: dwDTFormat |= DT_CENTER; break; case AlignRight: dwDTFormat |= DT_RIGHT; break; case AlignLeft: default: dwDTFormat |= DT_LEFT; } UINT dwMoreFormat = 0; switch (cropping) { case CropCenter: dwMoreFormat |= WFE_DT_CROPCENTER; break; case CropLeft: dwMoreFormat |= WFE_DT_CROPLEFT; break; case CropRight: default: dwMoreFormat |= WFE_DT_CROPRIGHT; break; } CRect textRect(*lpColumnRect); textRect.top += 1; // Account for the slight padding. textRect.bottom -= 2; // Account for the slight padding and the divider line. CRect bgRect; // Compute background rectangle CIntlWin::DrawText(CS_UTF8, hdc, (char*)lpszString, -1, &bgRect, DT_CALCRECT | dwDTFormat); int w = bgRect.Width() + 2*COL_LEFT_MARGIN; if (w > textRect.Width()) w = textRect.Width(); bgRect.left = textRect.left; bgRect.top = textRect.top; bgRect.right = bgRect.left + w; bgRect.bottom = textRect.bottom; // Fill the background with the current brush (or frame if we don't have focus) if (theBrush) { if (ViewerHasFocus()) { CRect newRect(bgRect); if (hasFocus) { newRect.top +=1; newRect.bottom-=1; newRect.left+=1; newRect.right-=1; } ::FillRect(hdc, &newRect, theBrush); } ::FrameRect( hdc, &bgRect, theBrush); } // Adjust the text rectangle for the left and right margins textRect.left += COL_LEFT_MARGIN; textRect.right -= COL_LEFT_MARGIN; WFE_DrawTextEx( CS_UTF8, hdc, (LPTSTR) lpszString, iLength, &textRect, dwDTFormat, dwMoreFormat ); } int CRDFOutliner::DrawPipes ( int iLineNo, int iColNo, int offset, HDC hdc, void * pLineData ) { int iImageWidth = m_itemHeight - 3; // Account for the two pixel padding + the divider int iTriggerSize = 9; // This will need to be changed when custom triggers arrive. int iBarWidth = iTriggerSize / 2 + 1; // 5 pixels out of the 9. int iMaxX = offset + m_pColumn[ iColNo ]->iCol; int idx; int iDepth; uint32 flags; OutlinerAncestorInfo * pAncestor; GetTreeInfo ( m_iTopLine + iLineNo, &flags, &iDepth, &pAncestor ); RECT rect; rect.left = offset; rect.right = rect.left + iImageWidth; rect.top = iLineNo * m_itemHeight; rect.bottom = rect.top + m_itemHeight; for ( int i = 0; i < iDepth; i++ ) { if ( rect.right <= iMaxX ) { if ( m_bHasPipes && pAncestor && pAncestor[ i ].has_next && i > 0) // Ignore the outermost level. { // Draw the appropriate vertical bar. // bar should be 5 pixels wide. 1 black - 3 gray - 1 black. CDC* pDC = CDC::FromHandle(hdc); CBrush innerBrush(RGB(192,192,192)); CBrush outerBrush(RGB(128,128,128)); CRect barRect(rect); barRect.left += (iImageWidth - iBarWidth) / 2; barRect.right = barRect.left + iBarWidth; pDC->FrameRect(barRect, &outerBrush); barRect.left += 1; barRect.right -= 1; pDC->FillRect(barRect, &innerBrush); } } rect.left += iImageWidth; rect.right += iImageWidth; } if (rect.right <= iMaxX) { if (iDepth && m_bHasPipes) { // Draw the vertical bar. CDC* pDC = CDC::FromHandle(hdc); CBrush innerBrush(RGB(192,192,192)); CBrush outerBrush(RGB(128,128,128)); CRect barRect(rect); barRect.left += (iImageWidth - iBarWidth) / 2; barRect.right = barRect.left + iBarWidth; if (!pAncestor[iDepth].has_next) { barRect.bottom -= 2; // Move away from the divider and even supply a little padding. } if (!pAncestor[iDepth].has_prev) { barRect.top += 1; // Supply a little padding. } pDC->FrameRect(barRect, &outerBrush); barRect.left += 1; barRect.right -= 1; if (!pAncestor[iDepth].has_next) { barRect.bottom -= 1; // Actually get that frame onto the end } if (!pAncestor[iDepth].has_prev) { barRect.top += 1; // Get that frame onto the top. } pDC->FillRect(barRect, &innerBrush); } HT_Resource r = (HT_Resource)pLineData; if (r && HT_IsContainer(r) && m_bHasPipes) { // Draw the trigger CBrush outerTrigger(RGB(128,128,128)); CBrush innerTrigger(RGB(255,255,255)); CRect triggerRect(rect); triggerRect.top += (iImageWidth - iTriggerSize) / 2 + 2; // Account for the pixel of padding triggerRect.bottom = triggerRect.top + iTriggerSize; triggerRect.left += (iImageWidth - iTriggerSize) / 2; triggerRect.right = triggerRect.left + iTriggerSize; CDC* pDC = CDC::FromHandle(hdc); pDC->FillRect(triggerRect, &innerTrigger); pDC->FrameRect(triggerRect, &outerTrigger); // Draw the horizontal portion of the trigger cross HPEN pen = ::CreatePen(PS_SOLID, 1, RGB(0,0,0)); HPEN pOldPen = (HPEN)::SelectObject(hdc, pen); pDC->MoveTo(triggerRect.left + 2, triggerRect.top + (iTriggerSize / 2)); pDC->LineTo(triggerRect.right - 2, triggerRect.top + (iTriggerSize / 2)); // Draw the vertical portion of the trigger cross (only for closed containers) if (!HT_IsContainerOpen(r)) { pDC->MoveTo(triggerRect.left + (iTriggerSize / 2), triggerRect.top + 2); pDC->LineTo(triggerRect.left + (iTriggerSize / 2), triggerRect.bottom - 2); } ::SelectObject(hdc, pOldPen); VERIFY(::DeleteObject(pen)); } rect.left += iImageWidth; rect.right += iImageWidth; } if ( rect.right <= iMaxX ) { idx = TranslateIcon (pLineData); HT_Resource r = (HT_Resource)pLineData; if (!HT_IsSeparator(r)) { rect.top += 1; // Handle the padding. if (idx == HTFE_USE_CUSTOM_IMAGE) DrawArbitraryURL(r, rect.left, rect.top, 16, 16, hdc, ::GetBkColor(hdc), this, FALSE, HT_SMALLICON); else if (idx == HTFE_LOCAL_FILE) DrawLocalFileIcon(r, rect.left, rect.top, hdc); else m_pIUserImage->DrawTransImage ( idx, rect.left, rect.top, hdc ); } else return rect.left; } return rect.right + OUTLINE_TEXT_OFFSET; } void CRDFOutliner::ColumnsSwapped() { SetImageColumn(m_pColumn[0]->iCommand); } void CRDFOutliner::DestroyColumns() { m_Parent->DestroyColumns(); COutliner::DestroyColumns(); } CRect CRDFOutliner::GetColumnRect(int iLine, int column) { CRect rectColumn; rectColumn.top = (iLine-m_iTopLine) * m_itemHeight; rectColumn.bottom = rectColumn.top + m_itemHeight; rectColumn.left = rectColumn.right = 0; int iColumn, offset; int iDepth; uint32 flags; OutlinerAncestorInfo * pAncestor; GetTreeInfo ( iLine, &flags, &iDepth, &pAncestor ); for (iColumn = offset = 0; iColumn < m_iVisColumns; iColumn++) { if (m_pColumn[iColumn]->iCommand == m_idImageCol) { // Handle the image column (where the indentation is) int iImageWidth = GetIndentationWidth(); rectColumn.left = (iImageWidth * (iDepth+1)) + OUTLINE_TEXT_OFFSET + m_pIUserImage->GetImageWidth(); } else rectColumn.left = offset; rectColumn.right = offset + m_pColumn[ iColumn ]->iCol; if (m_pColumn[iColumn]->iCommand == (UINT)column) break; offset += m_pColumn[ iColumn ]->iCol; } return rectColumn; } char * CRDFOutliner::GetTextEditText(void) { char str[1000]; if(m_EditField) { int size = m_EditField->GetWindowText(str, 1000); if(size > 0) { // we need to convert to UTF8 from the // Edit Control charset return (char*) INTL_ConvertLineWithoutAutoDetect( INTL_GetCharSetID(INTL_DefaultTextWidgetCsidSel), CS_UTF8,(unsigned char*) str, size ); } } return NULL; } // Edit window routines void CRDFOutliner::EditTextChanged(char* text) { if (text != NULL) { // Do stuff CRDFCommandMap& map = m_Parent->GetColumnCommandMap(); CRDFColumn* theColumn = (CRDFColumn*)(map.GetCommand(m_nSelectedColumn)); HT_SetNodeData(m_Node, theColumn->GetToken(), theColumn->GetDataType(), text); delete []text; } } void CRDFOutliner::AddTextEdit() { BOOL bRtn = TRUE; if(!m_EditField) { m_EditField = new CRDFEditWnd(this); bRtn = m_EditField->Create(WS_BORDER | ES_AUTOHSCROLL, CRect(0,0,0,0), this, 0); } CRect rect; HDC hDC = ::GetDC(m_hWnd); HFONT hFont = WFE_GetUIFont(hDC); HFONT hOldFont = (HFONT)::SelectObject(hDC, hFont); TEXTMETRIC tm; GetTextMetrics(hDC, &tm); int height = tm.tmHeight; ::SelectObject(hDC, hOldFont); ::ReleaseDC(m_hWnd, hDC); rect = GetColumnRect(m_iSelection, m_nSelectedColumn); rect.top += 1; if (rect.left == rect.right) bRtn = FALSE; if(!bRtn) { delete m_EditField; m_EditField = NULL; } else { m_EditField->MoveWindow(rect); m_EditField->ShowWindow(SW_SHOW); HDC hDC = ::GetDC(m_hWnd); HFONT hFont = WFE_GetUIFont(hDC); CFont *font = (CFont*) CFont::FromHandle(hFont); m_EditField->SetFont(font); ::ReleaseDC(m_hWnd, hDC); m_EditField->SetFocus(); char* pUTF8Text = (char*)GetColumnText(m_nSelectedColumn, HT_GetNthItem(m_View, m_iSelection)); if (pUTF8Text) { // we need to convert from UTF8 from the // Edit Control charset char* pEditText = (char*) INTL_ConvertLineWithoutAutoDetect( CS_UTF8, INTL_GetCharSetID(INTL_DefaultTextWidgetCsidSel), (unsigned char*)pUTF8Text, strlen(pUTF8Text) ); m_EditField->SetSel(0,-1); m_EditField->ReplaceSel(pEditText); m_EditField->SetSel(0,-1); XP_FREEIF(pEditText); } } } void CRDFOutliner::RemoveTextEdit() { if(m_EditField) { m_EditField->ShowWindow(SW_HIDE); } } void CRDFOutliner::MoveToNextColumn() { int oldPos = GetColumnPos((UINT)m_nSelectedColumn); oldPos++; if (oldPos < (int)GetVisibleColumns()) { m_nSelectedColumn = GetColumnAtPos(oldPos); RemoveTextEdit(); } else { m_nSelectedColumn = GetColumnAtPos(0); RemoveTextEdit(); HT_Resource r = HT_GetNthItem(m_View, m_iSelection); if (r) HT_SetSelectedState(r, (PRBool)FALSE); m_iSelection++; m_iFocus = m_iSelection; HT_Resource r2 = HT_GetNthItem(m_View, m_iSelection); if (!r2) { m_iFocus = -1; m_iSelection = -1; m_Node = NULL; return; } CRDFCommandMap& map = m_Parent->GetColumnCommandMap(); CRDFColumn* theColumn = (CRDFColumn*)(map.GetCommand(m_nSelectedColumn)); BOOL isEditable = HT_IsNodeDataEditable(r2, theColumn->GetToken(), theColumn->GetDataType()); if (!isEditable) { m_iFocus = -1; m_iSelection = -1; m_Node = NULL; return; } HT_SetSelectedState(r2, (PRBool)TRUE); m_Node = r2; } AddTextEdit(); } void CRDFOutliner::OnTimer(UINT nID) { if (nID == IDT_EDITFOCUS) { if (m_hEditTimer != 0) { KillTimer(m_hEditTimer); m_hEditTimer = 0; } AddTextEdit(); return; } else if (nID == IDT_SPRINGLOAD) { if (m_hSpringloadTimer != 0) { KillTimer(m_hSpringloadTimer); m_hSpringloadTimer = 0; if (m_iDragSelection == m_iSpringloadSelection) { // Open the folder HT_Resource r = HT_GetNthItem(m_View, m_iDragSelection); if (r != NULL) { // Pop it open HT_SetOpenState(r, (PRBool)TRUE); // Add this folder to our list of springloaded folders m_SpringloadStack.AddHead((void*)r); } } } return; } else if (nID == IDT_DRAGRECT) { if (m_hDragRectTimer != 0) { KillTimer(m_hDragRectTimer); m_hDragRectTimer = 0; CRect rect; GetClientRect(&rect); if (m_MovePoint.y < m_itemHeight) { DragRectScroll(TRUE); m_hDragRectTimer = SetTimer(IDT_DRAGRECT, GetDragHeartbeat(), NULL); } else if (m_MovePoint.y > rect.bottom - m_itemHeight) { DragRectScroll(FALSE); m_hDragRectTimer = SetTimer(IDT_DRAGRECT, GetDragHeartbeat(), NULL); } } return; } COutliner::OnTimer(nID); } // DRAG AND DROP ROUTINES int CRDFOutliner::GetDragHeartbeat() { return RDF_DRAG_HEARTBEAT; } COleDataSource * CRDFOutliner::GetDataSource() { m_bNeedToClear = FALSE; // Hack. Just leave it here, and don't worry about it. COleDataSource * pDataSource = new COleDataSource; HANDLE hString = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE,1); pDataSource->CacheGlobalData(m_cfHTNode, hString); // The view is sufficient RDFGLOBAL_BeginDrag(pDataSource, m_View); return pDataSource; } void RDFGLOBAL_BeginDrag(COleDataSource* pDataSource, HT_View pView) { CLIPFORMAT cfBookmark = (CLIPFORMAT) RegisterClipboardFormat( NETSCAPE_HTNODE_FORMAT ); HGLOBAL hBookmark = GlobalAlloc( GMEM_DDESHARE | GMEM_ZEROINIT, sizeof(HT_View) ); if( hBookmark ) { HT_View* pBookmark = (HT_View*) GlobalLock( hBookmark ); *pBookmark = pView; GlobalUnlock( hBookmark); pDataSource->CacheGlobalData( cfBookmark, hBookmark ); } // Get the selected items and set up internet shortcut // drag if the item is not a container or separator. int selCount = 0; HT_Resource r = HT_GetNextSelection(pView, NULL); while (r != NULL) { if (!HT_IsDropTarget(r) && !HT_IsSeparator(r)) selCount++; r = HT_GetNextSelection(pView, r); } CString* titleArray = new CString[selCount]; CString* urlArray = new CString[selCount]; int i = -1; r = HT_GetNextSelection(pView, NULL); while (r != NULL) { if (!HT_IsDropTarget(r) && !HT_IsSeparator(r)) { i++; // Found one titleArray[i] = HT_GetNodeName(r); urlArray[i] = HT_GetNodeURL(r); } r = HT_GetNextSelection(pView, r); } DragMultipleShortcuts(pDataSource, titleArray, urlArray, selCount); delete []titleArray; delete []urlArray; } void RDFGLOBAL_DragTitleAndURL( COleDataSource *pDataSource, LPCSTR title, LPCSTR url ) { CLIPFORMAT cfBookmark = (CLIPFORMAT) RegisterClipboardFormat( NETSCAPE_BOOKMARK_FORMAT ); HGLOBAL hBookmark = GlobalAlloc( GMEM_DDESHARE | GMEM_ZEROINIT, sizeof(BOOKMARKITEM) ); if( hBookmark ) { LPBOOKMARKITEM pBookmark = (LPBOOKMARKITEM) GlobalLock( hBookmark ); PR_snprintf( pBookmark->szAnchor, sizeof(pBookmark->szAnchor),"%s", url ); PR_snprintf( pBookmark->szText, sizeof(pBookmark->szText),"%s", title ); GlobalUnlock( hBookmark); pDataSource->CacheGlobalData( cfBookmark, hBookmark ); } HGLOBAL hString = GlobalAlloc( GMEM_MOVEABLE|GMEM_DDESHARE, strlen( url ) + 1 ); if ( hString ) { LPSTR lpszString = (LPSTR) GlobalLock( hString ); strcpy( lpszString, url ); GlobalUnlock( hString ); pDataSource->CacheGlobalData( CF_TEXT, hString ); } // Do an internet shortcut drag DragInternetShortcut(pDataSource, title, url); } COutlinerDropTarget* CRDFOutliner::CreateDropTarget() { return new CRDFDropTarget(this); } BOOL CRDFOutliner::HighlightIfDragging(void) { if(m_iDragSelection != -1) { HT_Resource r = HT_GetNthItem(m_View, m_iDragSelection); if (r != NULL && HT_IsDropTarget(r) && (m_iDragSelectionLineThird == 2 || (GetSortColumn() != -1))) return TRUE; } return FALSE; } void CRDFOutliner::PaintDragLine(HDC hdc, CRect &rectColumn) { HPEN pen = ::CreatePen(PS_SOLID, 1, m_ForegroundColor); HPEN pOldPen = (HPEN)::SelectObject(hdc, pen); if(m_iDragSelectionLineThird == 1) { #ifdef XP_WIN32 MoveToEx(hdc, rectColumn.left, rectColumn.top, NULL); #else MoveTo(hdc, rectColumn.left, rectColumn.top); #endif LineTo(hdc, rectColumn.right, rectColumn.top); } else if(m_iDragSelectionLineThird == 3){ #ifdef XP_WIN32 MoveToEx(hdc, rectColumn.left, rectColumn.bottom -1, NULL); #else MoveTo(hdc, rectColumn.left, rectColumn.bottom - 1); #endif LineTo(hdc, rectColumn.right, rectColumn.bottom - 1); } ::SelectObject(hdc, pOldPen); VERIFY(::DeleteObject(pen)); } void CRDFOutliner::AcceptDrop( int iLineNo, COleDataObject *pDataObject, DROPEFFECT dropEffect ) { HT_Resource theNode = NULL; if (iLineNo >= 0) theNode = HT_GetNthItem(m_View, iLineNo); if (theNode == NULL) theNode = HT_TopNode(m_View); RDFGLOBAL_PerformDrop(pDataObject, theNode, m_iDragSelectionLineThird); m_SpringloadStack.RemoveAll(); } void RDFGLOBAL_PerformDrop(COleDataObject* pDataObject, HT_Resource theNode, int dragFraction) { if(!pDataObject) return; CLIPFORMAT cfHTNode = (CLIPFORMAT)RegisterClipboardFormat(NETSCAPE_HTNODE_FORMAT); CLIPFORMAT cfBookmark = (CLIPFORMAT)RegisterClipboardFormat(NETSCAPE_BOOKMARK_FORMAT); if(!pDataObject->IsDataAvailable(CF_TEXT) && !pDataObject->IsDataAvailable(cfHTNode) && !pDataObject->IsDataAvailable(cfBookmark) && !pDataObject->IsDataAvailable(CF_HDROP)) return; if(pDataObject->IsDataAvailable(cfHTNode)) { HT_View pView = NULL; HGLOBAL hBookmark = pDataObject->GetGlobalData(cfHTNode); HT_View* pBookmark = (HT_View*)GlobalLock(hBookmark); ASSERT(pBookmark); pView = *pBookmark; GlobalUnlock(hBookmark); DropPosition dropPosition = RDFGLOBAL_TranslateDropPosition(theNode, dragFraction); HT_Resource node = NULL; BOOL nothingSelected = TRUE; while (node = (HT_GetNextSelection(pView, node))) { nothingSelected = FALSE; if (dropPosition == DROP_BEFORE) HT_DropHTRAtPos(theNode, node, (PRBool)TRUE); else if (dropPosition == DROP_AFTER) HT_DropHTRAtPos(theNode, node, (PRBool)FALSE); else if (dropPosition == DROP_ON) HT_DropHTROn(theNode, node); else HT_DropHTROn(HT_GetParent(theNode), node); } if (nothingSelected) { // Use the top node of the view. HT_Resource node = HT_TopNode(pView); if (dropPosition == DROP_BEFORE) HT_DropHTRAtPos(theNode, node, (PRBool)TRUE); else if (dropPosition == DROP_AFTER) HT_DropHTRAtPos(theNode, node, (PRBool)FALSE); else if (dropPosition == DROP_ON) HT_DropHTROn(theNode, node); } } else if(pDataObject->IsDataAvailable(cfBookmark)) { HGLOBAL hBookmark = pDataObject->GetGlobalData(cfBookmark); LPBOOKMARKITEM pBookmark = (LPBOOKMARKITEM)GlobalLock(hBookmark); ASSERT(pBookmark); CString title(pBookmark->szText); CString url(pBookmark->szAnchor); GlobalUnlock(hBookmark); DropPosition dropPosition = RDFGLOBAL_TranslateDropPosition(theNode, dragFraction); if (dropPosition == DROP_BEFORE) HT_DropURLAndTitleAtPos(theNode, (char*)(const char*)url, (char*)(const char*)title, (PRBool)TRUE); else if (dropPosition == DROP_AFTER) HT_DropURLAndTitleAtPos(theNode, (char*)(const char*)url, (char*)(const char*)title, (PRBool)FALSE); else if (dropPosition == DROP_ON) HT_DropURLAndTitleOn(theNode, (char*)(const char*)url, (char*)(const char*)title); else HT_DropURLAndTitleOn(HT_GetParent(theNode), (char*)(const char*)url, (char*)(const char*)title); } else if (pDataObject->IsDataAvailable(CF_HDROP)) { HGLOBAL hGlobal = pDataObject->GetGlobalData(CF_HDROP); HDROP hDropInfo = (HDROP)hGlobal; // Get the number of files dropped int i_num = ::DragQueryFile(hDropInfo, (UINT)-1, NULL, 0); char ca_drop[_MAX_PATH]; CString csUnescapedUrl, csEscapedUrl; int i_loop; for(i_loop = 0; i_loop < i_num; i_loop++) { ::DragQueryFile(hDropInfo, i_loop, ca_drop, _MAX_PATH); // Convert to an acceptable URL. WFE_ConvertFile2Url(csUnescapedUrl, ca_drop); csEscapedUrl = WFE_EscapeURL(csUnescapedUrl); // Tell HT about the drop DropPosition dropPosition = RDFGLOBAL_TranslateDropPosition(theNode, dragFraction); if (dropPosition == DROP_BEFORE) HT_DropURLAtPos(theNode, (char*)(const char*)csEscapedUrl, (PRBool)TRUE); else if (dropPosition == DROP_AFTER) HT_DropURLAtPos(theNode, (char*)(const char*)csEscapedUrl, (PRBool)FALSE); else if (dropPosition == DROP_ON) HT_DropURLOn(theNode, (char*)(const char*)csEscapedUrl); else HT_DropURLOn(HT_GetParent(theNode), (char*)(const char*)csEscapedUrl); } GlobalUnlock(hGlobal); } else if (pDataObject->IsDataAvailable(CF_TEXT)) { HGLOBAL hString = pDataObject->GetGlobalData(CF_TEXT); char * pAddress = (char*)GlobalLock(hString); CString url(pAddress); GlobalUnlock(hString); DropPosition dropPosition = RDFGLOBAL_TranslateDropPosition(theNode, dragFraction); if (dropPosition == DROP_BEFORE) HT_DropURLAtPos(theNode, (char*)(const char*)url, (PRBool)TRUE); else if (dropPosition == DROP_AFTER) HT_DropURLAtPos(theNode, (char*)(const char*)url, (PRBool)FALSE); else if (dropPosition == DROP_ON) HT_DropURLOn(theNode, (char*)(const char*)url); else HT_DropURLOn(HT_GetParent(theNode), (char*)(const char*)url); } } void CRDFOutliner::InitializeClipFormats(void) { m_cfHTNode = (CLIPFORMAT)RegisterClipboardFormat(NETSCAPE_HTNODE_FORMAT); m_cfBookmark = (CLIPFORMAT)RegisterClipboardFormat(NETSCAPE_BOOKMARK_FORMAT); m_clipFormatArray[0] = m_cfHTNode; m_clipFormatArray[1] = m_cfBookmark; m_clipFormatArray[2] = CF_HDROP; m_clipFormatArray[3] = CF_TEXT; m_clipFormatArray[4] = 0; } CLIPFORMAT * CRDFOutliner::GetClipFormatList(void) { return m_clipFormatArray; } DROPEFFECT CRDFOutliner::DropSelect(int iLineNo, COleDataObject *object) { HT_Resource r = NULL; if (iLineNo >= 0) r = HT_GetNthItem(m_View, iLineNo); if (r == NULL) r = HT_TopNode(m_View); DROPEFFECT answer = RDFGLOBAL_TranslateDropAction(r, object, HT_IsDropTarget(r) ? m_iDragSelectionLineThird : m_iDragSelectionLineHalf); m_iCurrentDropAction = answer; if (iLineNo == m_iDragSelection && !m_bDragSectionChanged) return answer; if (m_iDragSelection != -1) InvalidateDragLine (m_iDragSelection, HT_IsDropTarget(r), HT_IsDropTarget(r) ? m_iOldLineThird : m_iOldLineHalf); m_iDragSelection = iLineNo; InvalidateDragLine (m_iDragSelection, HT_IsDropTarget(r), HT_IsDropTarget(r) ? m_iDragSelectionLineThird : m_iDragSelectionLineHalf); // Start the hover timer for folder springloading if (m_iDragSelection != -1) { if (r != NULL && HT_IsDropTarget(r) && !HT_IsContainerOpen(r) && m_iCurrentDropAction != DROPEFFECT_NONE) { m_iSpringloadSelection = m_iDragSelection; m_hSpringloadTimer = SetTimer(IDT_SPRINGLOAD, SPRINGLOAD_DELAY, NULL); } } // Check for springload closing time if (!m_SpringloadStack.IsEmpty()) { // There are some springloaded folders that might need to be closed. POSITION p = m_SpringloadStack.GetHeadPosition(); HT_Resource r = (HT_Resource)m_SpringloadStack.GetNext(p); int count = (int)HT_GetCountVisibleChildren(r); int index = (int)HT_GetNodeIndex(m_View, r); if (m_iDragSelection < index || m_iDragSelection == -1 || m_iDragSelection > index + count) { m_SpringloadStack.RemoveHead(); HT_SetOpenState(r, (PRBool)FALSE); if (m_iDragSelection > index + count) m_iDragSelection -= count; } } return answer; } DropPosition RDFGLOBAL_TranslateDropPosition(HT_Resource dropTarget, int position) { HT_Resource targetParent = HT_GetParent(dropTarget); BOOL sortImposed = FALSE; if (targetParent != NULL) sortImposed = !HT_ContainerSupportsNaturalOrderSort(targetParent); // Is a sort imposed on the parent? DropPosition res; if (!sortImposed) // Can only drop/before or after if sort is not imposed on the view. { if (position == 1) { // Drop before res = DROP_BEFORE; // In upper half of selection (for non-containers) or bottom third // of selection (for containers). Drop before. } else if (position == 3 || (position == 2 && !HT_IsDropTarget(dropTarget))) { // Drop after if we're in the bottom half (for non-containers) or bottom third (for containers) res = DROP_AFTER; // In lower third of selection. Drop after. } else res = DROP_ON; // We're a container and right in the middle of selection. Drop on. } else if (HT_IsDropTarget(dropTarget)) { res = DROP_ON; // If a sort is imposed and we're over a container, drop into that. } else res = DROP_ON_PARENT; // Otherwise, we'll drop into the parent container and let the sort // put it where it's supposed to go. return res; } DROPEFFECT RDFGLOBAL_TranslateDropAction(HT_Resource dropTarget, COleDataObject* pDataObject, int position) { HT_DropAction res; CLIPFORMAT cfHTNode = (CLIPFORMAT)RegisterClipboardFormat(NETSCAPE_HTNODE_FORMAT); CLIPFORMAT cfBookmark = (CLIPFORMAT)RegisterClipboardFormat(NETSCAPE_BOOKMARK_FORMAT); if (dropTarget == NULL) return DROPEFFECT_NONE; DropPosition dropPosition = RDFGLOBAL_TranslateDropPosition(dropTarget, position); if(pDataObject->IsDataAvailable(cfHTNode)) { HT_View pView = NULL; HGLOBAL hBookmark = pDataObject->GetGlobalData(cfHTNode); HT_View* pBookmark = (HT_View*)GlobalLock(hBookmark); ASSERT(pBookmark); pView = *pBookmark; GlobalUnlock(hBookmark); HT_Resource node = HT_GetNextSelection(pView, NULL); BOOL nothingSelected = TRUE; while (node != NULL) { nothingSelected = FALSE; HT_DropAction res2; if (dropPosition == DROP_BEFORE) res2 = HT_CanDropHTRAtPos(dropTarget, node, (PRBool)TRUE); else if (dropPosition == DROP_AFTER) res2 = HT_CanDropHTRAtPos(dropTarget, node, (PRBool)FALSE); else if (dropPosition == DROP_ON) res2 = HT_CanDropHTROn(dropTarget, node); else res2 = HT_CanDropHTROn(HT_GetParent(dropTarget), node); if (res2 == DROP_NOT_ALLOWED) { res = DROP_NOT_ALLOWED; break; } res = res2; node = HT_GetNextSelection(pView, node); } if (nothingSelected) { // Use the top node of the view. HT_Resource node = HT_TopNode(pView); // Should only enter this code when buttons from the selector bar are being dragged. if (dropPosition == DROP_BEFORE) res = HT_CanDropHTRAtPos(dropTarget, node, (PRBool)TRUE); else if (dropPosition == DROP_AFTER) res = HT_CanDropHTRAtPos(dropTarget, node, (PRBool)FALSE); else if (dropPosition == DROP_ON) res = HT_CanDropHTROn(dropTarget, node); else res = HT_CanDropHTROn(HT_GetParent(dropTarget), node); } } else if (pDataObject->IsDataAvailable(cfBookmark)) { HGLOBAL hBookmark = pDataObject->GetGlobalData(cfBookmark); LPBOOKMARKITEM pBookmark = (LPBOOKMARKITEM)GlobalLock(hBookmark); ASSERT(pBookmark); CString title(pBookmark->szText); CString url(pBookmark->szAnchor); GlobalUnlock(hBookmark); if (dropPosition == DROP_BEFORE) res = HT_CanDropURLAtPos(dropTarget, (char*)(const char*)url, (PRBool)TRUE); else if (dropPosition == DROP_AFTER) res = HT_CanDropURLAtPos(dropTarget, (char*)(const char*)url, (PRBool)FALSE); else if (dropPosition == DROP_ON) res = HT_CanDropURLOn(dropTarget, (char*)(const char*)url); else res = HT_CanDropURLOn(HT_GetParent(dropTarget), (char*)(const char*)url); } else if (pDataObject->IsDataAvailable(CF_HDROP)) { HGLOBAL hGlobal = pDataObject->GetGlobalData(CF_HDROP); HDROP hDropInfo = (HDROP)hGlobal; // Get the number of files dropped int i_num = ::DragQueryFile(hDropInfo, (UINT)-1, NULL, 0); char ca_drop[_MAX_PATH]; CString csUnescapedUrl, csEscapedUrl; int i_loop; HT_DropAction res2; for(i_loop = 0; i_loop < i_num; i_loop++) { ::DragQueryFile(hDropInfo, i_loop, ca_drop, _MAX_PATH); // Convert to an acceptable URL. WFE_ConvertFile2Url(csUnescapedUrl, ca_drop); csEscapedUrl = WFE_EscapeURL(csUnescapedUrl); // Tell HT about the drop if (dropPosition == DROP_BEFORE) res2 = HT_CanDropURLAtPos(dropTarget, (char*)(const char*)csEscapedUrl, (PRBool)TRUE); else if (dropPosition == DROP_AFTER) res2 = HT_CanDropURLAtPos(dropTarget, (char*)(const char*)csEscapedUrl, (PRBool)FALSE); else if (dropPosition == DROP_ON) res2 = HT_CanDropURLOn(dropTarget, (char*)(const char*)csEscapedUrl); else res2 = HT_CanDropURLOn(HT_GetParent(dropTarget), (char*)(const char*)csEscapedUrl); if (res2 == DROP_NOT_ALLOWED) { res = DROP_NOT_ALLOWED; break; } res = res2; } GlobalUnlock(hGlobal); } else if (pDataObject->IsDataAvailable(CF_TEXT)) { HGLOBAL hString = pDataObject->GetGlobalData(CF_TEXT); char * pAddress = (char*)GlobalLock(hString); CString url(pAddress); GlobalUnlock(hString); if (dropPosition == DROP_BEFORE) res = HT_CanDropURLAtPos(dropTarget, (char*)(const char*)url, (PRBool)TRUE); else if (dropPosition == DROP_AFTER) res = HT_CanDropURLAtPos(dropTarget, (char*)(const char*)url, (PRBool)FALSE); else if (dropPosition == DROP_ON) res = HT_CanDropURLOn(dropTarget, (char*)(const char*)url); else res = HT_CanDropURLOn(HT_GetParent(dropTarget), (char*)(const char*)url); } switch (res) { case DROP_NOT_ALLOWED: return DROPEFFECT_NONE; case COPY_MOVE_CONTENT: case COPY_MOVE_LINK: return DROPEFFECT_MOVE; default: return DROPEFFECT_COPY; } } // RDFDropTarget Overridden Funcs BOOL CRDFDropTarget::OnDrop( CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point) { m_dwOldTicks = 0; CRDFOutliner* pOutliner = (CRDFOutliner*)m_pOutliner; if(!pDataObject || !pOutliner) return(FALSE); if (!pOutliner->RecognizedFormat(pDataObject)) return FALSE; pOutliner->m_ptHit = point; pOutliner->AcceptDrop( point.y < 0 ? -1 : pOutliner->GetDropLine(), pDataObject, dropEffect); pOutliner->EndDropSelect(); return(TRUE); } DROPEFFECT CRDFDropTarget::OnDragEnter( CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point) { DROPEFFECT res = OnDragOver(pWnd, pDataObject, dwKeyState, point); CRDFOutliner* pOutliner = (CRDFOutliner*)m_pOutliner; pOutliner->m_bDataSourceInWindow = TRUE; if ( res != DROPEFFECT_NONE && point.y >= 0) { m_pOutliner->Invalidate(); m_pOutliner->UpdateWindow(); } return res; } DROPEFFECT CRDFDropTarget::OnDragOver( CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point) { DROPEFFECT effect = DROPEFFECT_NONE; CRDFOutliner* pOutliner = (CRDFOutliner*)m_pOutliner; if (pOutliner->RecognizedFormat(pDataObject)) { RECT rect; pWnd->GetClientRect(&rect); if ( point.y < pOutliner->m_itemHeight && point.y >= 0) { DragScroll(TRUE); effect |= DROPEFFECT_SCROLL; } else if ( point.y > ( rect.bottom - pOutliner->m_itemHeight ) ) { DragScroll(FALSE); effect |= DROPEFFECT_SCROLL; } else { m_dwOldTicks = 0; } pOutliner->m_ptHit = point; effect |= pOutliner->DropSelect(point.y < 0 ? -1 : pOutliner->LineFromPoint(point), pDataObject); // Default is to move if ( ( effect & DROPEFFECT_MOVE) && (dwKeyState & MK_CONTROL) ) effect = (effect & ~DROPEFFECT_MOVE) | DROPEFFECT_COPY; } return effect; } void CRDFDropTarget::OnDragLeave(CWnd* pWnd) { CRDFOutliner* pOutliner = (CRDFOutliner*)m_pOutliner; for (POSITION p = pOutliner->m_SpringloadStack.GetHeadPosition(); p != NULL; ) { HT_Resource r = (HT_Resource)(pOutliner->m_SpringloadStack.GetNext(p)); HT_SetOpenState(r, (PRBool)FALSE); } pOutliner->m_SpringloadStack.RemoveAll(); pOutliner->m_bDataSourceInWindow = FALSE; pOutliner->m_iDragSelection = -1; pOutliner->Invalidate(); pOutliner->UpdateWindow(); } // ======================================================================== BEGIN_MESSAGE_MAP(CRDFOutlinerParent,COutlinerParent) ON_WM_DESTROY() ON_WM_PAINT ( ) END_MESSAGE_MAP() CRDFOutlinerParent::CRDFOutlinerParent(HT_Pane thePane, HT_View theView) { CRDFOutliner* theOutliner = new CRDFOutliner(this, thePane, theView); m_pOutliner = theOutliner; } BOOL CRDFOutlinerParent::PreCreateWindow(CREATESTRUCT& cs) { BOOL bRet = CWnd::PreCreateWindow(cs); //#ifdef XP_WIN32 // cs.dwExStyle |= WS_EX_CLIENTEDGE; //#endif return bRet; } void CRDFOutlinerParent::OnDestroy() { // Save prefs might happen here... COutlinerParent::OnDestroy(); } COutliner* CRDFOutlinerParent::GetOutliner ( ) { return m_pOutliner; } void CRDFOutlinerParent::OnPaint ( ) { CPaintDC pdc ( this ); if ( !m_pOutliner || m_bDisableHeaders ) return; // Read in our values. CRDFOutliner* pRDFLiner = (CRDFOutliner*)m_pOutliner; HT_View view = pRDFLiner->GetHTView(); if (view == NULL) return; HT_Resource top = HT_TopNode(view); // Foreground color void* data; HT_GetTemplateData(top, gNavCenter->columnHeaderFGColor, HT_COLUMN_STRING, &data); if (data) WFE_ParseColor((char*)data, &m_ForegroundColor); else m_ForegroundColor = RGB(0,0,0); // background color HT_GetTemplateData(top, gNavCenter->columnHeaderBGColor, HT_COLUMN_STRING, &data); if (data) WFE_ParseColor((char*)data, &m_BackgroundColor); else m_BackgroundColor = RGB(192,192,192); // Background image URL m_BackgroundImageURL = ""; HT_GetTemplateData(top, gNavCenter->columnHeaderBGURL, HT_COLUMN_STRING, &data); if (data) m_BackgroundImageURL = (char*)data; m_pBackgroundImage = NULL; // Clear out the BG image. HPALETTE pOldPalette = NULL; if (sysInfo.m_iBitsPerPixel < 16 && (::GetDeviceCaps(pdc.m_hDC, RASTERCAPS) & RC_PALETTE)) { // Use the palette, since we have less than 16 bits per pixel and are // using a palette-based device. HPALETTE hPalette = WFE_GetUIPalette(GetParentFrame()); ::SelectPalette(pdc.m_hDC, hPalette, FALSE); // Find the nearest match in our palette for our colors. ResolveToPaletteColor(m_BackgroundColor, hPalette); ResolveToPaletteColor(m_ForegroundColor, hPalette); } int i, offset; // we might use these in the for() loop below --- make sure // they stay in scope since we don't restore into the CDC until // the end of the routine HFONT hOldFont = (HFONT) pdc.SelectObject ( m_hToolFont ); COLORREF cOldText = pdc.SetTextColor(m_ForegroundColor); int nOldMode = pdc.SetBkMode(TRANSPARENT); CBrush bgBrush(m_BackgroundColor); CBrush fgBrush(m_ForegroundColor); CRect rectClient; GetClientRect ( &rectClient ); // Do the background painting if (m_BackgroundImageURL != "") { // There's a background that needs to be drawn. m_pBackgroundImage = LookupImage(m_BackgroundImageURL, NULL); } BOOL shouldPaintBG = m_pBackgroundImage && m_pBackgroundImage->FrameSuccessfullyLoaded(); if (shouldPaintBG) { PaintBackground(pdc, rectClient, m_pBackgroundImage); } int iMaxHeaderWidth = rectClient.right - m_iPusherWidth; for ( i = offset = 0; (i < (int)m_pOutliner->GetVisibleColumns()) && (offset < iMaxHeaderWidth); i++ ) { BOOL bDep = m_pOutliner->m_pColumn[ i ]->bDepressed && m_pOutliner->m_pColumn[ i ]->bIsButton; CRect rect( offset, 0, m_pOutliner->m_pColumn[ i ]->iCol + offset, m_iHeaderHeight ); if (rect.right > iMaxHeaderWidth ) { rect.right = iMaxHeaderWidth; } CRect rcInter; if ( ::IntersectRect ( &rcInter, &pdc.m_ps.rcPaint, &rect ) ) { CRect rcText = rect; if (!shouldPaintBG) ::FillRect(pdc.m_hDC, &rcText, bgBrush ); rcText.InflateRect(1, 0, 0, 0); ::FrameRect(pdc.m_hDC, &rcText, fgBrush); DrawColumnHeader( pdc.m_hDC, rcText, i ); } offset += m_pOutliner->m_pColumn[ i ]->iCol; } // Fill in the gap on the right if (offset < iMaxHeaderWidth) { RECT rect = {offset, 0, iMaxHeaderWidth, m_iHeaderHeight}; CRect rcInter; if ( IntersectRect( &rcInter, &pdc.m_ps.rcPaint, &rect ) ) { CRect rcText = rect; if (!shouldPaintBG) ::FillRect(pdc.m_hDC, &rcText, bgBrush ); rcText.InflateRect(1, 0, 0, 0); ::FrameRect(pdc.m_hDC, &rcText, fgBrush ); } } CRect rect(rectClient.right - m_iPusherWidth, 0, rectClient.right, m_iHeaderHeight ); CRect iRect; if ( iRect.IntersectRect ( &pdc.m_ps.rcPaint, &rect ) ) { int idxImage; rect.InflateRect(1,0,1,0); if (!shouldPaintBG) ::FillRect ( pdc.m_hDC, &rect, bgBrush ); ::FrameRect( pdc.m_hDC, &rect, fgBrush ); m_iPusherState = pusherNone; if ( m_pOutliner->m_iNumColumns > 1 ) { if (m_pOutliner->GetVisibleColumns() > 1) { m_iPusherState |= pusherRight; } if (int(m_pOutliner->GetVisibleColumns()) < m_pOutliner->m_iNumColumns) { m_iPusherState |= pusherLeft; } } CRect divider(rect.left, rect.top, rect.left + rect.Width()/2, rect.bottom); ::FrameRect(pdc.m_hDC, ÷r, fgBrush); POINT ptBitmap; RECT rect2 = rect; // Draw left pusher rect2.right = (rect.left + rect.right + 1) / 2; ptBitmap.x = (rect2.left + rect2.right + 1) / 2 - 4; ptBitmap.y = (rect2.top + rect2.bottom + 1) / 2 - 4; if ( m_iPusherRgn == pusherLeft ) { ptBitmap.x++; ptBitmap.y++; } idxImage = m_iPusherState & pusherLeft ? IDX_PUSHLEFT : IDX_PUSHLEFTI; m_pIImage->DrawTransImage( idxImage, ptBitmap.x, ptBitmap.y, &pdc); //DrawButtonRect( pdc.m_hDC, rect2, m_iPusherRgn == pusherLeft ); // Draw right pusher rect2.left = rect2.right; rect2.right = rect.right; ptBitmap.x = (rect2.left + rect2.right + 1) / 2 - 4; ptBitmap.y = (rect2.top + rect2.bottom + 1) / 2 - 4; if ( m_iPusherRgn == pusherRight ) { ptBitmap.x++; ptBitmap.y++; } idxImage = m_iPusherState & pusherRight ? IDX_PUSHRIGHT : IDX_PUSHRIGHTI; m_pIImage->DrawTransImage( idxImage, ptBitmap.x, ptBitmap.y, &pdc); //DrawButtonRect( pdc.m_hDC, rect2, m_iPusherRgn == pusherRight ); } pdc.SelectObject ( hOldFont ); pdc.SetTextColor ( cOldText ); pdc.SetBkMode( nOldMode ); if (m_bEnableFocusFrame) { HBRUSH hBrush = NULL; if (GetFocus() == m_pOutliner) hBrush = ::CreateSolidBrush( GetSysColor( COLOR_HIGHLIGHT ) ); else hBrush = ::CreateSolidBrush( GetSysColor( COLOR_WINDOW ) ); RECT clientRect; GetClientRect(&clientRect); ::FrameRect( pdc.m_hDC, &clientRect, hBrush ); VERIFY(DeleteObject( hBrush )); } if (sysInfo.m_iBitsPerPixel < 16 && (::GetDeviceCaps(pdc.m_hDC, RASTERCAPS) & RC_PALETTE)) { ::SelectPalette(pdc.m_hDC, pOldPalette, FALSE); } } void CRDFOutlinerParent::CreateColumns ( void ) { // Retrieve the columns from RDF CRDFOutliner* theOutliner = (CRDFOutliner*)m_pOutliner; HT_View theView = theOutliner->GetHTView(); HT_Cursor columnCursor = HT_NewColumnCursor(theView); char* columnName; uint32 columnWidth; void* token; uint32 tokenType; UINT index = 0; int visibleCount = 0; while (HT_GetNextColumn(columnCursor, &columnName, &columnWidth, &token, &tokenType)) { // We have retrieved a new column. Contruct a front end column object CRDFColumn* newColumn = new CRDFColumn(columnName, columnWidth, token, tokenType); index = (UINT)columnMap.AddCommand(newColumn); m_pOutliner->AddColumn(columnName, index, 50, 10000, ColumnVariable, 100); PRBool visible = HT_GetColumnVisibility(theView, token, tokenType); if (visible) visibleCount++; } if (visibleCount == 0) visibleCount++; HT_DeleteColumnCursor(columnCursor); // If column headers aren't shown, assume only one visible column. // Whether or not to show column headers void* data; HT_GetTemplateData(HT_TopNode(theView), gNavCenter->showColumnHeaders, HT_COLUMN_STRING, &data); BOOL show = TRUE; if (data) { char* answer = (char*)data; show = stricmp(answer, "No"); } if (!show) visibleCount = 1; m_pOutliner->SetVisibleColumns(visibleCount); m_pOutliner->SetImageColumn(m_pOutliner->m_pColumn[0]->iCommand); // Make it so RECT rcClient; m_pOutliner->GetClientRect(&rcClient); ((CRDFOutliner*)m_pOutliner)->OnSize(0, rcClient.right, rcClient.bottom); Invalidate(); theOutliner->ToggleModes(); } BOOL CRDFOutlinerParent::RenderData( int iColumn, CRect & rect, CDC &dc, LPCTSTR text ) { CRDFOutliner *pOutliner = (CRDFOutliner *)m_pOutliner; if( !pOutliner ) { return FALSE; } if( pOutliner->GetSortType() == HT_NO_SORT) { return FALSE; } MSG_COMMAND_CHECK_STATE sortType = (iColumn == pOutliner->GetSortColumn()) ? MSG_Checked : MSG_Unchecked; if( sortType != MSG_Checked ) { return FALSE; } int idxImage = (pOutliner->GetSortType() % 2) ? IDX_SORTINDICATORUP : IDX_SORTINDICATORDOWN; UINT dwDTFormat = DT_NOCLIP | DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER; RECT rectText = rect; rectText.left += 4; rectText.right -= 5; rectText.right -= 22; m_pIImage->DrawTransImage( idxImage, rectText.right + 4, (rect.top + rect.bottom) / 2 - 4, &dc ); WFE_DrawTextEx( CS_UTF8, dc.m_hDC, (LPTSTR) text, -1, &rectText, dwDTFormat, WFE_DT_CROPRIGHT ); return TRUE; } BOOL CRDFOutlinerParent::ColumnCommand( int iColumn ) { CRDFOutliner *pOutliner = (CRDFOutliner *)m_pOutliner; int enSortType = pOutliner->GetSortType(); if (pOutliner->GetSortColumn() != iColumn) { // May need to resort in back end (not sure) enSortType = HT_NO_SORT; } if (enSortType == HT_SORT_ASCENDING) enSortType = HT_SORT_DESCENDING; else if (enSortType == HT_SORT_DESCENDING) enSortType = HT_NO_SORT; else enSortType = HT_SORT_ASCENDING; pOutliner->SetSortType( enSortType ); if (enSortType == HT_NO_SORT) pOutliner->SetSortColumn(-1); else pOutliner->SetSortColumn( iColumn ); CRDFColumn* theColumn = (CRDFColumn*)(columnMap.GetCommand(iColumn)); BOOL sort = TRUE; if (enSortType == HT_SORT_ASCENDING) sort = FALSE; pOutliner->SetSelectedColumn(iColumn); HT_SetSortColumn(pOutliner->GetHTView(), enSortType == HT_NO_SORT ? NULL : theColumn->GetToken(), theColumn->GetDataType(), (PRBool)sort); return TRUE; } void CRDFOutlinerParent::Initialize() { CreateColumns ( ); CRDFOutliner* theOutliner = (CRDFOutliner*)m_pOutliner; m_pOutliner->SetTotalLines( HT_GetItemListCount(theOutliner->GetHTView()) ); } // ======================================================================= // RDFEditWnd - Class that controls the in-place editing of column values // ======================================================================= BOOL CRDFEditWnd::PreTranslateMessage ( MSG * msg ) { if ( msg->message == WM_KEYDOWN) { switch(msg->wParam) { case VK_RETURN: { m_pOwner->EditTextChanged(m_pOwner->GetTextEditText()); m_pOwner->RemoveTextEdit(); return TRUE; } case VK_ESCAPE: m_pOwner->RemoveTextEdit(); break; case VK_TAB: m_pOwner->EditTextChanged(m_pOwner->GetTextEditText()); m_pOwner->MoveToNextColumn(); return TRUE; } } return CEdit::PreTranslateMessage ( msg ); } ////////////////////////////////////////////////////////////////////////// // Messages for CRDFEditWnd ////////////////////////////////////////////////////////////////////////// BEGIN_MESSAGE_MAP(CRDFEditWnd, CEdit) //{{AFX_MSG_MAP(CWnd) ON_WM_DESTROY() ON_WM_SETFOCUS() ON_WM_KILLFOCUS() //}}AFX_MSG_MAP END_MESSAGE_MAP() void CRDFEditWnd::OnDestroy( ) { delete this; } void CRDFEditWnd::OnSetFocus(CWnd* pOldWnd) { CEdit::OnSetFocus(pOldWnd); } void CRDFEditWnd::OnKillFocus( CWnd* pNewWnd ) { CEdit::OnKillFocus(pNewWnd); m_pOwner->FocusCheck(pNewWnd, FALSE); m_pOwner->RemoveTextEdit(); } // ========================================================================= // RDF Content View IMPLEMENT_DYNAMIC(CRDFContentView, CView) BEGIN_MESSAGE_MAP(CRDFContentView, CView) //{{AFX_MSG_MAP(CMainFrame) // NOTE - the ClassWizard will add and remove mapping macros here. // DO NOT EDIT what you see in these blocks of generated code ! ON_WM_CREATE() ON_WM_SIZE() ON_WM_SETFOCUS() //}}AFX_MSG_MAP END_MESSAGE_MAP() CRDFContentView::CRDFContentView() { m_pOutlinerParent = NULL; m_pHTMLView = NULL; m_pNavBar = NULL; } int CRDFContentView::OnCreate ( LPCREATESTRUCT lpCreateStruct ) { int iRetVal = CView::OnCreate ( lpCreateStruct ); LPCTSTR lpszClass = AfxRegisterWndClass( CS_VREDRAW, ::LoadCursor(NULL, IDC_ARROW)); m_pNavBar = new CNavTitleBar(); m_pOutlinerParent = new CRDFOutlinerParent(); m_pOutlinerParent->Create( lpszClass, _T("NSOutlinerParent"), WS_VISIBLE|WS_CHILD|WS_CLIPCHILDREN, CRect(0,0,100,100), this, 101 ); m_pHTMLView = wfe_CreateNavCenterHTMLPain(m_hWnd); m_pNavBar->Create(NULL, "", WS_CHILD | WS_VISIBLE, CRect(0,0,100,100), this, NC_IDW_NAVMENU); CRDFOutliner* pOutliner = (CRDFOutliner*)(GetOutlinerParent()->GetOutliner()); HT_View v = pOutliner->GetHTView(); return iRetVal; } CRDFContentView::~CRDFContentView() { CRDFOutliner* pOutliner = (CRDFOutliner*)(GetOutlinerParent()->GetOutliner()); HT_View v = pOutliner->GetHTView(); HT_SetViewFEData(v, NULL); XP_UnregisterNavCenter(HT_GetPane(v)); HT_DeletePane(HT_GetPane(v)); delete m_pNavBar; delete m_pOutlinerParent; } void CRDFContentView::OnSize ( UINT nType, int cx, int cy ) { CView::OnSize ( nType, cx, cy ); if (IsWindow(m_pOutlinerParent->m_hWnd)) { int titleHeight = m_pNavBar->GetHeightBasedOnProperties(); m_pNavBar->MoveWindow(0,0, cx, titleHeight); int htmlPaneHeight = 0; CRDFOutliner* pOutliner = (CRDFOutliner*)(m_pOutlinerParent->GetOutliner()); HT_View theView = pOutliner->GetHTView(); BOOL percent = FALSE; if (theView) { HT_Resource topNode = HT_TopNode(theView); if (HT_HasHTMLPane(theView)) { htmlPaneHeight = 150; // Need to get the HTML pane's height. char* data = HT_HTMLPaneHeight(theView); int height = 0; if (data) { CString strData(data); int length = strData.GetLength(); if (strData[length-1] == '%') { percent = TRUE; strData = strData.Left(length-1); } else if (strData[0] == '*') { percent = TRUE; strData = "100"; } else percent = FALSE; height = atoi(strData); if (percent) htmlPaneHeight = (int)((height/100.0) * (cy - titleHeight)); else htmlPaneHeight = height; } } } int outlinerHeight = cy-titleHeight-htmlPaneHeight; m_pOutlinerParent->MoveWindow ( 0, titleHeight, cx, outlinerHeight); ::MoveWindow(m_pHTMLView->GetPane(), 0, titleHeight + outlinerHeight, cx, htmlPaneHeight, TRUE); } } void CRDFContentView::OnSetFocus ( CWnd * pOldWnd ) { m_pOutlinerParent->SetFocus ( ); } void CRDFContentView::SwitchHTViews(HT_View newView) { m_pOutlinerParent->SetHTView(newView); m_pOutlinerParent->GetOutliner()->DestroyColumns(); CreateColumns(); } void CRDFContentView::OnKillFocus(CWnd* pNewWnd) { } // Functionality for the RDF Tree Embedded in HTML (Added 3/10/98 by Dave Hyatt). // The event handler. Only cares about tree events, so we'll just pass everything to the // tree view. void embeddedTreeNotifyProcedure (HT_Notification ns, HT_Resource n, HT_Event whatHappened, void *token, uint32 tokenType) { CRDFOutliner* theOutliner = (CRDFOutliner*)HT_GetViewFEData(HT_GetView(n)); if (theOutliner) theOutliner->HandleEvent(ns, n, whatHappened); } CRDFContentView* CRDFContentView::DisplayRDFTreeFromPane(CWnd* pParent, int xPos, int yPos, int width, int height, HT_Pane thePane, CCreateContext* pContext) { // Create the windows CRect rClient(xPos, yPos, xPos+width, yPos+height); CRDFContentView* newView = new CRDFContentView(); newView->Create(NULL, "", WS_CHILD | WS_VISIBLE, rClient, pParent, NC_IDW_OUTLINER, pContext); // Get the parent COutlinerParent* newParent = newView->GetOutlinerParent(); ((CRDFOutlinerParent*)newParent)->SetHTView(HT_GetSelectedView(thePane)); // Initialize the columns, etc. ((CRDFOutlinerParent*)newParent)->Initialize(); // Retrieve the RDF Outliner. CRDFOutliner* pOutliner = (CRDFOutliner*)newParent->GetOutliner(); // Set our FE data to be the outliner. HT_SetViewFEData(HT_GetSelectedView(thePane), pOutliner); // Explain who the title bar belongs to. CNavTitleBar* pTitleBar = newView->GetTitleBar(); pTitleBar->SetHTView(HT_GetSelectedView(thePane)); pOutliner->SetTitleBar(pTitleBar); // Register the HTML pane to load the URL if (HT_HasHTMLPane(HT_GetSelectedView(thePane))) { XP_RegisterViewHTMLPane(HT_GetSelectedView(thePane), newView->GetHTMLView()->GetContext()); char* data; HT_Resource top = HT_TopNode(HT_GetSelectedView(thePane)); HT_GetTemplateData (top, gNavCenter->RDF_HTMLURL, HT_COLUMN_STRING, (void**)&data); if (data) { XP_GetURLForView(HT_GetSelectedView(thePane), data); } } theApp.m_pRDFCX->TrackRDFWindow(newView); return newView; } CRDFContentView* CRDFContentView::DisplayRDFTreeFromResource(CWnd* pParent, int xPos, int yPos, int width, int height, HT_Resource node, CCreateContext* pContext) { HT_Notification ns = new HT_NotificationStruct; XP_BZERO(ns, sizeof(HT_NotificationStruct)); ns->notifyProc = embeddedTreeNotifyProcedure; ns->data = NULL; HT_Pane thePane = HT_PaneFromResource(HT_GetRDFResource(node), ns, PR_FALSE, PR_TRUE, PR_TRUE); // Now call our helper function return DisplayRDFTreeFromPane(pParent, xPos, yPos, width, height, thePane, pContext); } CRDFContentView* CRDFContentView::DisplayRDFTreeFromSHACK(MWContext *pContext, CWnd* pParent, int xPos, int yPos, int width, int height, char* url, char* templateType, int32 param_count, char** param_names, char** param_values) { HT_Notification ns = new HT_NotificationStruct; XP_BZERO(ns, sizeof(HT_NotificationStruct)); ns->notifyProc = embeddedTreeNotifyProcedure; ns->data = NULL; // Construct the pane and give it our notification struct HT_Pane thePane = HT_PaneFromURL(pContext, url, templateType, ns, 0, param_count, param_names, param_values); // Now call our helper function return DisplayRDFTreeFromPane(pParent, xPos, yPos, width, height, thePane); } // Function to grab an RDF context extern "C" MWContext* FE_GetRDFContext(void) { MWContext *pRetval = NULL; if(theApp.m_pRDFCX) { pRetval = theApp.m_pRDFCX->GetContext(); } return(pRetval); } // The context's GetDialogOwner() function. CWnd* CRDFCX::GetDialogOwner() const { if (m_pCurrentRDFWindow == NULL || m_pCurrentRDFWindow->m_hWnd == NULL) return NULL; else { // Need to redesign if (m_pCurrentRDFWindow->GetParent() != NULL && m_pCurrentRDFWindow->GetParent()->GetParent() != NULL && m_pCurrentRDFWindow->GetParent()->GetParent()->IsKindOf(RUNTIME_CLASS(CRDFContentView))) { CRDFOutliner* pOutliner = (CRDFOutliner*)m_pCurrentRDFWindow; pOutliner->SetTemporaryRetainOnPopup(TRUE); } return m_pCurrentRDFWindow->GetTopLevelFrame(); } } // ================================================================== // HTFEDATA Functions (found in rdfacc.h) // ================================================================== void CHTFEData::FlushIconInfo() { // Just remove the HICONs from the local file cache. m_LocalFileCache.RemoveAll(); // Need to iterate over all the elements in the custom URL cache and destroy the images. POSITION pos = m_CustomURLCache.GetStartPosition(); void* pData; CString key; while (pos != NULL) { m_CustomURLCache.GetNextAssoc(pos, key, pData); CRDFImage* pImage = (CRDFImage*)pData; delete pImage; } } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // CDialogPRMT dialog void stdPrint (void* data, char* str) { fprintf((FILE*)data, str); } CExportRDF::CExportRDF(CWnd* pParent /*=NULL*/) : CDialog(CExportRDF::IDD, pParent) { m_csTitle = _T(""); //{{AFX_DATA_INIT(CDialogPRMT) m_csAns = ""; //}}AFX_DATA_INIT } void CExportRDF::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CDialogPRMT) DDX_Text(pDX, IDC_PROMPT_ANS, m_csAns); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CExportRDF, CDialog) //{{AFX_MSG_MAP(CDialogPRMT) // NOTE: the ClassWizard will add message map macros here //}}AFX_MSG_MAP END_MESSAGE_MAP()