home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / winfe / rdfliner.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  85.8 KB  |  3,208 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. // RDFLiner Implementation.  Created by Dave Hyatt.
  20.  
  21. #include "stdafx.h"
  22. #include "mainfrm.h"
  23. #include "hiddenfr.h"
  24. #include "rdf.h"
  25. #include "htrdf.h"
  26. #include "rdfliner.h"
  27. #include "shcut.h"
  28. #include "shcutdlg.h"
  29. #include "prefapi.h"
  30. #include "netsvw.h"
  31. #include "cxsave.h"
  32. #include "fegui.h"
  33. #include "nethelp.h"
  34. #include "time.h"
  35.  
  36. CMapStringToPtr CHTFEData::m_LocalFileCache(40);
  37. CMapStringToPtr CHTFEData::m_CustomURLCache(20);
  38.  
  39. extern "C" {
  40. #include "xpgetstr.h"
  41. extern int XP_BKMKS_LESS_THAN_ONE_HOUR_AGO;
  42. extern int XP_BKMKS_DAYS_AGO;
  43. extern int XP_BKMKS_HOURS_AGO;
  44. };
  45.  
  46. // Some tooltip stuff
  47. #define TIP_WAITING    1
  48. #define TIP_SHOWING    2
  49. #define TIP_SHOWN    3
  50. #define TIP_HEARTBEAT    100
  51. #define TIP_DELAY        250
  52.  
  53. // Focus/timer stuff for edit wnds
  54. #define IDT_EDITFOCUS 16412
  55. #define IDT_SPRINGLOAD 16413
  56. #define IDT_DRAGRECT 16414
  57.  
  58. #define EDIT_DELAY 500
  59. #define SPRINGLOAD_DELAY 300
  60. #define RDF_DRAG_HEARTBEAT 125 // Faster than COutliner's DRAG_HEARTBEAT
  61.  
  62. // Click location stuff
  63. #define CLICKED_BACKGROUND 0
  64. #define CLICKED_TRIGGER 1
  65. #define CLICKED_LINE 2
  66.  
  67. // Used in painting
  68. #define COL_LEFT_MARGIN    ((m_cxChar+1)/2)
  69. #define OUTLINE_TEXT_OFFSET 8
  70.  
  71. #define HTFE_USE_CUSTOM_IMAGE -1
  72. #define HTFE_LOCAL_FILE -2
  73.  
  74. #define HT_NO_SORT -1
  75. #define HT_SORT_ASCENDING 1
  76. #define HT_SORT_DESCENDING 0
  77.  
  78. // Function to make a pretty date string
  79. #define SECONDS_PER_DAY        86400L
  80. void FormatDateTime( CTime &tmDate, CString &csFormatDate )
  81. {
  82.     //
  83.     // Get locale info
  84.     //
  85.     static char cName[] = "intl" ;
  86.     TCHAR szSepDate[2], szSepTime[2];    
  87.     GetProfileString( cName, "sDate", "/", szSepDate, sizeof(szSepDate) );
  88.     GetProfileString( cName, "sTime", ":", szSepTime, sizeof(szSepTime) );    
  89.  
  90.     TCHAR szAM[9], szPM[9];
  91.     GetProfileString( cName, "s1159", "AM", szAM, sizeof(szAM) );
  92.     GetProfileString( cName, "s2359", "PM", szPM, sizeof(szPM) );    
  93.  
  94.     int iDate = GetProfileInt( cName, "iDate", 0 );
  95.     int iTime = GetProfileInt( cName, "iTime", 0 );
  96.   
  97.     TCHAR szBuffer[64];
  98.     switch( iDate )
  99.     {
  100.         default:
  101.         case 0: // Month-Day-Year 
  102.         {
  103.             wsprintf( szBuffer, "%d%s%d%s%d", tmDate.GetMonth(), szSepDate, tmDate.GetDay(), szSepDate, tmDate.GetYear() );
  104.             break;
  105.         }
  106.         
  107.         case 1: // Day-Month-Year 
  108.         {
  109.             wsprintf( szBuffer, "%d%s%d%s%d", tmDate.GetDay(), szSepDate, tmDate.GetMonth(), szSepDate, tmDate.GetYear() );
  110.             break;
  111.         }
  112.  
  113.         case 2: // Year-Month-Day     
  114.         {
  115.             wsprintf( szBuffer, "%d%s%d%s%d", tmDate.GetYear(), szSepDate, tmDate.GetMonth(), szSepDate, tmDate.GetDay() );
  116.             break;
  117.         }
  118.     }
  119.     
  120.     _tcscat( szBuffer, " " );
  121.     
  122.     TCHAR *pszTime = &szBuffer[_tcslen( szBuffer )];
  123.     
  124.     switch( iTime )
  125.     {
  126.         default:
  127.         case 0: // AM/PM 12-hour
  128.         {
  129.             BOOL bPM = FALSE;
  130.             int iHour = tmDate.GetHour();
  131.             if( iHour > 11 )
  132.             {
  133.                 bPM = TRUE;
  134.                 iHour -= 12;
  135.             }
  136.             
  137.             iHour = iHour ? iHour : 12;
  138.             
  139.             wsprintf( pszTime, "%d%s%.2d %s", iHour, szSepTime, tmDate.GetMinute(), (TCHAR *)(bPM ? szPM : szAM) );
  140.             break;
  141.         }
  142.         
  143.         case 1: // 24-hour
  144.         {
  145.             wsprintf( pszTime, "%d%s%.2d", tmDate.GetHour(), szSepTime, tmDate.GetMinute() );
  146.             break;
  147.         }
  148.     }
  149.     
  150.     csFormatDate = (const char *)szBuffer;
  151. }
  152.  
  153.  
  154. void HTFE_MakePrettyDate(char* buffer, time_t lastVisited)
  155. {
  156.   buffer[0] = 0;
  157.   time_t today = XP_TIME();
  158.   int elapsed = today - lastVisited;
  159.  
  160.   if (elapsed < SECONDS_PER_DAY) 
  161.   {
  162.     int32 hours = (elapsed + 1800L) / 3600L;
  163.     if (hours < 1) 
  164.     {
  165.       strcpy(buffer, XP_GetString(XP_BKMKS_LESS_THAN_ONE_HOUR_AGO));
  166.     }
  167.     sprintf(buffer, XP_GetString(XP_BKMKS_HOURS_AGO), hours);
  168.   } 
  169.   else if (elapsed < (SECONDS_PER_DAY * 31)) 
  170.   {
  171.       sprintf(buffer, XP_GetString(XP_BKMKS_DAYS_AGO),
  172.               (elapsed + (SECONDS_PER_DAY / 2)) / SECONDS_PER_DAY);
  173.   } 
  174.   else 
  175.   {
  176.       CString csFormatDate;
  177.       CTime ctDate( lastVisited );
  178.       FormatDateTime( ctDate, csFormatDate );
  179.       _tcscpy( buffer, (const char *)csFormatDate );
  180.   }
  181. }
  182.  
  183. BEGIN_MESSAGE_MAP(CRDFOutliner, COutliner)
  184.     //{{AFX_MSG_MAP(CMainFrame)
  185.         // NOTE - the ClassWizard will add and remove mapping macros here.
  186.         //    DO NOT EDIT what you see in these blocks of generated code !
  187.     ON_WM_PAINT()
  188.     ON_WM_SETFOCUS()
  189.     ON_WM_KILLFOCUS()
  190.     ON_WM_LBUTTONDOWN()
  191.     ON_WM_LBUTTONUP()
  192.     ON_WM_MOUSEMOVE()
  193.     ON_WM_RBUTTONDOWN()
  194.     ON_WM_RBUTTONUP()
  195.     ON_WM_CREATE()
  196.     ON_WM_TIMER()
  197.     //}}AFX_MSG_MAP
  198. END_MESSAGE_MAP()
  199.  
  200. CRDFOutliner::CRDFOutliner (HT_Pane thePane, HT_View theView, CRDFOutlinerParent* theParent)
  201. :m_pAncestor(NULL), m_Pane(thePane), m_View(theView), m_Parent(theParent), m_EditField(NULL),
  202. m_nSortType(HT_NO_SORT), m_nSortColumn(HT_NO_SORT), m_hEditTimer(0), m_hDragRectTimer(0),
  203. m_bNeedToClear(FALSE), m_nSelectedColumn(0), m_bDoubleClick(FALSE), m_Node(NULL), 
  204. m_bDataSourceInWindow(FALSE), m_NavMenuBar(NULL)
  205. {
  206.     ApiApiPtr(api);
  207.     m_pUnkUserImage = api->CreateClassInstance(APICLASS_IMAGEMAP,NULL,(APISIGNATURE)IDB_BOOKMARKS);
  208.     if (m_pUnkUserImage) {
  209.         m_pUnkUserImage->QueryInterface(IID_IImageMap,(LPVOID*)&m_pIUserImage);
  210.         ASSERT(m_pIUserImage);
  211.         if (!m_pIUserImage->GetResourceID())
  212.             m_pIUserImage->Initialize(IDB_BOOKMARKS,16,16);
  213.     }
  214. }
  215.  
  216. CRDFOutliner::~CRDFOutliner ()
  217. {
  218.     if (m_pUnkUserImage) {
  219.         if (m_pIUserImage)
  220.             m_pUnkUserImage->Release();
  221.     }
  222.  
  223.     delete m_pAncestor;
  224. }
  225.  
  226. int CRDFOutliner::OnCreate(LPCREATESTRUCT lpCreateStruct)
  227. {
  228.     int iRetVal = COutliner::OnCreate(lpCreateStruct);
  229.     DragAcceptFiles(FALSE);
  230.     return iRetVal;
  231. }
  232.  
  233. void CRDFOutliner::HandleEvent(HT_Notification ns, HT_Resource n, HT_Event whatHappened) 
  234. {
  235.     if (whatHappened == HT_EVENT_NODE_OPENCLOSE_CHANGED)
  236.     {
  237.         FinishExpansion(HT_GetNodeIndex(m_View, n));
  238.     }
  239.     else if (whatHappened == HT_EVENT_NODE_SELECTION_CHANGED)
  240.     {
  241.         int i = HT_GetNodeIndex(m_View, n);
  242.         InvalidateLine(i);
  243.     }
  244.     else if (whatHappened == HT_EVENT_NODE_ADDED)
  245.     {
  246.         HT_Resource par = HT_GetParent(n);
  247.         int toggle = -1;
  248.  
  249.         if (par != NULL)
  250.             toggle = HT_GetNodeIndex(m_View, par);
  251.  
  252.         FinishExpansion(toggle);
  253.     }
  254.     else if (whatHappened == HT_EVENT_VIEW_SORTING_CHANGED)
  255.     {
  256.         if (m_Node)
  257.         {        
  258.             int index =    HT_GetNodeIndex(m_View, m_Node);
  259.             m_iFocus = index;
  260.         }
  261.         Invalidate();
  262.     }
  263.     else if (whatHappened == HT_EVENT_NODE_EDIT)
  264.     {
  265.         m_Node = n;
  266.         m_iSelection = m_iFocus = HT_GetNodeIndex(m_View, n);
  267.         m_nSelectedColumn = GetColumnAtPos(0);
  268.  
  269.         AddTextEdit();
  270.  
  271.     }
  272.     else if (whatHappened == HT_EVENT_NODE_DELETED_DATA ||
  273.              whatHappened == HT_EVENT_NODE_DELETED_NODATA)
  274.     {
  275.         m_iFocus = -1;
  276.     }
  277.     else if (whatHappened == HT_EVENT_VIEW_REFRESH)
  278.     {
  279.         SetTotalLines(HT_GetItemListCount(m_View));
  280.         Invalidate();
  281.         UpdateWindow();
  282.     }
  283.     else if (whatHappened == HT_EVENT_NODE_VPROP_CHANGED)
  284.     {
  285.         // Invalidate a single line
  286.         if (n)
  287.         {        
  288.             int index =    HT_GetNodeIndex(m_View, n);
  289.             InvalidateLine(index);
  290.         }
  291.     }
  292. }
  293.  
  294.  
  295. LPCTSTR CRDFOutliner::GetColumnText ( UINT iColumn, void * pLineData )
  296. {
  297.     void* nodeData;
  298.     time_t dateVal;
  299.     struct tm* time;
  300.     
  301.     HT_Resource pEntry = (HT_Resource)pLineData;
  302.     CRDFCommandMap& map = m_Parent->GetColumnCommandMap(); 
  303.     CRDFColumn* theColumn = (CRDFColumn*)(map.GetCommand(iColumn));
  304.         
  305.     if (pEntry && HT_GetNodeData(pEntry, theColumn->GetToken(), theColumn->GetDataType(), &nodeData)
  306.         && nodeData)
  307.     {
  308.         char* buffer = theColumn->GetStorageBuffer();
  309.         switch (theColumn->GetDataType())
  310.         {
  311.             case HT_COLUMN_DATE_STRING:
  312.                 if ((dateVal = (time_t)atol((char *)nodeData)) == 0)    break;
  313.                 if ((time = localtime(&dateVal)) == NULL)    break;
  314.                 HTFE_MakePrettyDate(buffer, dateVal);
  315.                 break;
  316.             case HT_COLUMN_DATE_INT:
  317.                 if ((time = localtime((time_t *) &nodeData)) == NULL)    break;
  318.                 HTFE_MakePrettyDate(buffer, (time_t)nodeData);
  319.                 break;
  320.             case HT_COLUMN_INT:
  321.                 sprintf(buffer,"%d",(int)nodeData);
  322.                 break;
  323.             case HT_COLUMN_STRING:
  324.                 strcpy(buffer, (char*)nodeData);
  325.                 break;
  326.         }
  327.  
  328.         return buffer;
  329.     }
  330.     return NULL;
  331. }
  332.  
  333. void * CRDFOutliner::AcquireLineData ( int iLine )
  334.     // Grab this resource
  335.     if (GetTotalLines() <= iLine)
  336.         return NULL;
  337.  
  338.     HT_Resource r = HT_GetNthItem(m_View, iLine);
  339.  
  340.     if (r != NULL)
  341.     {
  342.         int indent = HT_GetItemIndentation(r);
  343.         BOOL hasPrev = HT_ItemHasBackwardSibling(r);
  344.         BOOL hasNext = HT_ItemHasForwardSibling(r);
  345.  
  346.         if (m_bPaintingFirstObject || indent > m_nSizeOfAncestorArray)
  347.         {
  348.             OutlinerAncestorInfo* oldInfo = m_pAncestor;
  349.             
  350.             if (m_bPaintingFirstObject)
  351.             {
  352.                 m_nSizeOfAncestorArray = indent;
  353.                 oldInfo = NULL;
  354.             }
  355.  
  356.             m_pAncestor = new OutlinerAncestorInfo[indent];
  357.             
  358.             // Fill in the ancestor values.
  359.             copyAncestorValues(r, m_nSizeOfAncestorArray, oldInfo, m_pAncestor);
  360.             m_nSizeOfAncestorArray = indent;
  361.  
  362.             delete []oldInfo;
  363.         }
  364.         
  365.         
  366.         m_pAncestor[indent-1].has_next = hasNext;
  367.         m_pAncestor[indent-1].has_prev = hasPrev;
  368.     }        
  369.  
  370.     return r;
  371. }
  372.  
  373. void CRDFOutliner::ReleaseLineData ( void * pLineData )
  374. {
  375. }
  376.  
  377. void CRDFOutliner::GetTreeInfo( int iLine, uint32 * pFlags, int * iDepth, 
  378.                                      OutlinerAncestorInfo ** pAncestor )
  379. {
  380.     HT_Resource r = HT_GetNthItem(m_View, iLine);
  381.     if (r == NULL)
  382.         return;
  383.  
  384.     if (pFlags)
  385.         *pFlags = (uint32)HT_IsContainer(r);
  386.     if (iDepth)
  387.         *iDepth = HT_GetItemIndentation(r)-1;
  388.     
  389.     if (pAncestor)
  390.         *pAncestor = m_pAncestor;
  391. }
  392.  
  393. void CRDFOutliner::copyAncestorValues(HT_Resource r, int numItems, OutlinerAncestorInfo* oldInfo, OutlinerAncestorInfo* newInfo)
  394. {
  395.     if (oldInfo != NULL)
  396.     {
  397.         for (int i = 0; i < numItems; i++)
  398.         {
  399.             newInfo[i].has_next = oldInfo[i].has_next;
  400.             newInfo[i].has_prev = oldInfo[i].has_prev;
  401.         }
  402.     }
  403.     else
  404.     {
  405.         // Have to acquire ALL the data.
  406.         HT_Resource currNode = r;
  407.         for (int i = numItems-1; i >= 0; i--)
  408.         {
  409.             newInfo[i].has_next = HT_ItemHasForwardSibling(currNode);
  410.             newInfo[i].has_prev = HT_ItemHasBackwardSibling(currNode);
  411.             currNode = HT_GetParent(currNode);
  412.         }
  413.     }
  414. }
  415.  
  416. BOOL CRDFOutliner::IsSelected(int iLine)
  417. {
  418.     HT_Resource r = HT_GetNthItem(m_View, iLine);
  419.     return (r != NULL) && (HT_IsSelected(r));
  420. }
  421.  
  422. HFONT CRDFOutliner::GetLineFont ( void * pLineData )
  423. {
  424.     // Will need to hack this for aliases/shortcuts? (italics!)
  425.     /*HT_Resource r = (HT_Resource)pLineData;
  426.     char* url = HT_GetNodeURL(r);
  427.  
  428.     if (url && !IsLocalFile(url))
  429.         return m_hItalFont;
  430.     */
  431.  
  432.     return m_hRegFont;
  433. }
  434.  
  435. int CRDFOutliner::TranslateIcon ( void * pData )
  436. {
  437.    HT_Resource data = (HT_Resource)pData;
  438.    char* pURL = HT_GetNodeSmallIconURL(data);
  439.  
  440.    //TRACE("%s\n", pURL);
  441.     
  442.    if (strncmp("icon", pURL, 4) == 0)
  443.    {
  444.        // Icon URL
  445.         if ((strcmp("icon/small:folder/closed", pURL) == 0) ||
  446.             (strcmp("icon/small:folder,history/closed", pURL) == 0))
  447.             return IDX_BOOKMARKCLOSED;
  448.  
  449.         if ((strcmp("icon/small:folder/open", pURL) == 0) ||
  450.             (strcmp("icon/small:folder,history/open", pURL) == 0))
  451.             return IDX_BOOKMARKOPEN;
  452.  
  453.         if (strcmp("icon/small:url", pURL) == 0)
  454.             return IDX_BOOKMARK;
  455.  
  456.         if ((strcmp("icon/small:file/local", pURL) == 0) ||
  457.             (strcmp("icon/small:folder/local,closed", pURL) == 0) ||
  458.             (strcmp("icon/small:folder/local,open", pURL) == 0))
  459.             return HTFE_LOCAL_FILE;
  460.  
  461.         // Catchall code for unknown ICON urls
  462.         if (HT_IsContainer(data))
  463.         {
  464.             if (HT_IsContainerOpen(data))
  465.                 return IDX_BOOKMARKOPEN;
  466.             else return IDX_BOOKMARKCLOSED;
  467.         }
  468.  
  469.         return IDX_BOOKMARK;
  470.    }
  471.  
  472.    // Handle the arbitrary URL case
  473.    return HTFE_USE_CUSTOM_IMAGE;   
  474. }
  475.  
  476. int CRDFOutliner::TranslateIconFolder( void *pData )
  477. {
  478.    HT_Resource data = (HT_Resource)pData;
  479.  
  480.    if (data) 
  481.    {
  482.        if (HT_IsContainer(data))
  483.        {
  484.            if (HT_IsContainerOpen(data))
  485.            {
  486.                return OUTLINER_OPENFOLDER;
  487.            }
  488.            else
  489.            {
  490.                return OUTLINER_CLOSEDFOLDER;
  491.            }
  492.        }
  493.    }
  494.     
  495.    return OUTLINER_ITEM;
  496. }
  497.  
  498. void CRDFOutliner::LoadComplete(HT_Resource pResource)
  499. {
  500.     InvalidateLine(HT_GetNodeIndex(m_View, pResource));
  501. }
  502.  
  503. // Functions used to draw custom images (either local file system icons or arbitrary image URLs)
  504. HICON DrawLocalFileIcon(HT_Resource r, int left, int top, HDC hDC) 
  505. {
  506.     char* pLocalName = NULL;
  507.     HICON hIcon = FetchLocalFileIcon(r);
  508.     
  509.     if (hIcon)
  510.     {
  511.         // Now we draw this bad boy.
  512.         DrawIconEx(hDC, left, top, hIcon, 0, 0, 0, NULL, DI_NORMAL);    
  513.     }
  514.  
  515.     return hIcon;
  516. }
  517.  
  518. NSNavCenterImage* DrawArbitraryURL(HT_Resource r, int left, int top, int imageWidth, int imageHeight, HDC hDC, COLORREF bkColor, 
  519.                       CCustomImageObject* pObject, BOOL largeIcon)
  520. {
  521.     NSNavCenterImage* pImage = FetchCustomIcon(r, pObject, largeIcon);
  522.     if (pImage && pImage->CompletelyLoaded()) 
  523.     {
  524.         // Now we draw this bad boy.
  525.         if (pImage->m_BadImage) 
  526.         { 
  527.             // display broken icon.
  528.             HDC tempDC = ::CreateCompatibleDC(hDC);
  529.             HBITMAP hOldBmp = (HBITMAP)::SelectObject(tempDC,  NSNavCenterImage::m_hBadImageBitmap);
  530.             ::StretchBlt(hDC, 
  531.                      left, top,
  532.                      imageWidth, imageHeight, 
  533.                      tempDC, 0, 0, 
  534.                      imageWidth, imageHeight, SRCCOPY);
  535.             ::SelectObject(tempDC, hOldBmp);
  536.             ::DeleteDC(tempDC);
  537.         }
  538.         else if (pImage->bits ) 
  539.         {
  540.             // Center the image. 
  541.             long width = pImage->bmpInfo->bmiHeader.biWidth;
  542.             long height = pImage->bmpInfo->bmiHeader.biHeight;
  543.             int xoffset = (imageWidth-width)/2;
  544.             int yoffset = (imageHeight-height)/2;
  545.             if (xoffset < 0) xoffset = 0;
  546.             if (yoffset < 0) yoffset = 0;
  547.             if (width > imageWidth) width = imageWidth;
  548.             if (height > imageHeight) height = imageHeight;
  549.  
  550.             HPALETTE hPal = WFE_GetUIPalette(NULL);
  551.             HPALETTE hOldPal = ::SelectPalette(hDC, hPal, TRUE);
  552.  
  553.             ::RealizePalette(hDC);
  554.             
  555.             if (pImage->maskbits) 
  556.             {
  557.                 WFE_StretchDIBitsWithMask(hDC, TRUE, NULL,
  558.                     left+xoffset, top+xoffset,
  559.                     width, height,
  560.                     0, 0, width, height,
  561.                     pImage->bits, pImage->bmpInfo,
  562.                     pImage->maskbits, FALSE, bkColor);
  563.             }
  564.             else 
  565.             {
  566.                 ::StretchDIBits(hDC,
  567.                     left+xoffset, top+xoffset,
  568.                     width, height,
  569.                     0, 0, width, height, pImage->bits, pImage->bmpInfo, DIB_RGB_COLORS,
  570.                     SRCCOPY);
  571.             }
  572.  
  573.         ::SelectPalette(hDC, hOldPal, TRUE);
  574.         }
  575.     }
  576.  
  577.     return pImage;
  578. }
  579.  
  580. BOOL IsLocalFile(const char* pURL)
  581. {
  582.     return strncmp(pURL, "file:", 5) == 0;
  583. }
  584.  
  585. BOOL IsExecutableURL(const char* pURL)
  586. {
  587.     char* pLocalName = NULL;
  588.     if (!XP_ConvertUrlToLocalFile(pURL, &pLocalName))
  589.         return FALSE;
  590.     
  591.     pLocalName = NET_UnEscape(pLocalName);
  592.  
  593.     // Do a FindExecutable.  If the filenames match, we win.
  594.     char execName[_MAX_PATH];
  595.     if (FEU_FindExecutable(pLocalName, execName, FALSE))
  596.     {
  597.         // Well, there's at least SOMETHING.
  598.         // See if it matches us.
  599.         char answerString[_MAX_PATH];
  600.         strcpy(answerString, pLocalName);
  601.         char execString[_MAX_PATH];
  602.         strcpy(execString, execName);
  603.         
  604. #ifdef _WIN32
  605.         GetShortPathName(pLocalName, answerString, _MAX_PATH);
  606.         GetShortPathName(execName, execString, _MAX_PATH);
  607. #endif // _WIN32
  608.  
  609.         if (!stricmp(answerString, execString))
  610.           return TRUE;
  611.     }
  612.  
  613.     if (pLocalName)
  614.         XP_FREE(pLocalName);
  615.  
  616.     return FALSE;
  617. }
  618.  
  619. // The expansion handler
  620. int CRDFOutliner::ToggleExpansion (int iLine)
  621. {
  622.     PRBool openp;
  623.     HT_Resource pEntry = HT_GetNthItem(m_View, iLine);
  624.     if (pEntry && HT_IsContainer(pEntry))
  625.     {
  626.         HT_GetOpenState(pEntry, &openp);
  627.         HT_SetOpenState(pEntry, (PRBool)(!openp));
  628.     }
  629.     return 0;
  630. }
  631.  
  632. HICON FetchLocalFileIcon(HT_Resource r)
  633. {
  634.     HICON hIcon = NULL;
  635.     CString hashString(HT_GetNodeURL(r));
  636.         
  637.     if (hashString.GetLength() < 12) // Hack.  It's a disk volume.
  638.     {
  639.         // Hash disk drives based on URL.
  640.     }
  641.     else if (HT_IsContainer(r))
  642.     {
  643.         // We're a directory.
  644.         if (HT_IsContainerOpen(r))
  645.             hashString = "open folder";
  646.         else hashString = "closed folder";
  647.     }
  648.     else
  649.     {
  650.         // We're a file.
  651.         int index = hashString.ReverseFind('.');
  652.         if (index == -1)
  653.             hashString = "no extension";
  654.         else hashString = hashString.Right(hashString.GetLength() - index);
  655.     }
  656.         
  657.     void* hashPtr;
  658.     char* pLocalName = NULL;
  659.     if (CHTFEData::m_LocalFileCache.Lookup(hashString, hashPtr))
  660.     {
  661.         // We found an icon in the icon cache.
  662.         hIcon = (HICON)hashPtr;
  663.     }
  664.     else 
  665.     {
  666.         XP_ConvertUrlToLocalFile(HT_GetNodeURL(r), &pLocalName);
  667.         pLocalName = NET_UnEscape(pLocalName);
  668.  
  669.         SHFILEINFO shInfo;
  670.         shInfo.hIcon = NULL;
  671.  
  672.         if (HT_IsContainer(r) && HT_IsContainerOpen(r))
  673.             SHGetFileInfo(pLocalName, 0, &shInfo, sizeof(shInfo), SHGFI_OPENICON | SHGFI_ICON | SHGFI_SMALLICON);
  674.         else SHGetFileInfo(pLocalName, 0, &shInfo, sizeof(shInfo), SHGFI_ICON | SHGFI_SMALLICON);
  675.         
  676.         if(shInfo.hIcon)
  677.         {
  678.             hIcon = shInfo.hIcon;
  679.  
  680.             // Add to the local file cache.
  681.             CHTFEData::m_LocalFileCache.SetAt(hashString, (void*)hIcon);
  682.         }
  683.  
  684.         if (pLocalName)
  685.             XP_FREE(pLocalName);
  686.     }
  687.  
  688.     return hIcon;
  689. }
  690.  
  691. NSNavCenterImage* FetchCustomIcon(HT_Resource r, CCustomImageObject* imageObject, BOOL largeIcon)
  692. {
  693.     NSNavCenterImage* pImage = NULL;
  694.     CString hashString;
  695.     if (largeIcon)
  696.         hashString = HT_GetNodeLargeIconURL(r);
  697.     else hashString = HT_GetNodeSmallIconURL(r);
  698.     
  699.     if (strncmp("icon/large:workspace", hashString, 20) == 0)
  700.     {
  701.         char name[8];
  702.         int ret = sscanf(hashString, "icon/large:workspace,%s", name);
  703.         if (ret != 0) 
  704.             hashString = CString("about:") + name + ".gif";
  705.     }
  706.     else if (strncmp("icon/large:folder", hashString, 17) == 0)
  707.     {
  708.         hashString = "about:personal.gif";
  709.     }
  710.  
  711.     // Find the image.
  712.     void* pData;
  713.     if (CHTFEData::m_CustomURLCache.Lookup(hashString, pData))
  714.     {
  715.         pImage = (NSNavCenterImage*)pData;
  716.  
  717.         // Add ourselves to the callback list if the image hasn't completely loaded.
  718.         if (!pImage->CompletelyLoaded())
  719.         {
  720.             // The image is currently loading.  Register ourselves with the image so that we will get called
  721.             // when the image finishes loading.
  722.             CIconCallbackInfo* iconCallbackInfo = new CIconCallbackInfo(imageObject, r);
  723.             pImage->resourceList.AddHead(iconCallbackInfo);  
  724.         }
  725.     }
  726.     else
  727.     {
  728.         // Create a new NavCenter image.
  729.         CIconCallbackInfo* iconCallbackInfo = new CIconCallbackInfo(imageObject, r);
  730.         pImage = new NSNavCenterImage((char*)(const char*)hashString, iconCallbackInfo);
  731.         CHTFEData::m_CustomURLCache.SetAt(hashString, pImage);
  732.     }
  733.  
  734.     return pImage;
  735. }
  736.  
  737.  
  738. IconType DetermineIconType(HT_Resource pNode, BOOL largeIcon)
  739.    IconType returnValue;
  740.    if (pNode != NULL)
  741.    {
  742.         char* pURL = largeIcon? HT_GetNodeLargeIconURL(pNode) : HT_GetNodeSmallIconURL(pNode);
  743.         TRACE("%s\n", pURL);
  744.         if (strncmp("icon", pURL, 4) != 0)
  745.         {
  746.             // Time to load a custom image.
  747.             returnValue = ARBITRARY_URL;
  748.         }
  749.         else if ((strncmp("icon/large:workspace", pURL, 20) == 0) ||
  750.                  (strncmp("icon/large:folder", pURL, 17) == 0))
  751.         {
  752.             returnValue = ARBITRARY_URL;
  753.         }
  754.         else if (IsLocalFile(HT_GetNodeURL(pNode)))
  755.         {
  756.             returnValue = LOCAL_FILE;
  757.         }
  758.         else returnValue = BUILTIN_BITMAP;
  759.    }
  760.    else returnValue = BUILTIN_BITMAP;
  761.  
  762.    return returnValue;
  763. }
  764.  
  765. // The callback for finishing the expansion
  766. void CRDFOutliner::FinishExpansion(int toggleIndex)
  767. {
  768.     int iCount = GetTotalLines();
  769.     int newCount = HT_GetItemListCount(m_View);
  770.     SetTotalLines(newCount);  // Update the outliner's visible lines
  771.     
  772.     int iDelta = newCount - iCount;
  773.     int iSel = GetFocusLine();
  774.     if (iSel > toggleIndex) {
  775.         if (iDelta > 0) {
  776.             iSel += iDelta;
  777.         } else {
  778.             if (iSel < (toggleIndex - iDelta)) {
  779.                 iSel = toggleIndex;
  780.             } else {
  781.                 iSel += iDelta;
  782.             }
  783.         }
  784.         if (iSel != GetFocusLine()) 
  785.         {
  786.             m_iFocus = m_iSelection = iSel;
  787.             InvalidateLine(m_iFocus);
  788.         }
  789.     }
  790.     
  791.     if ( iDelta > 0 ) 
  792.     {
  793.         iDelta = iDelta > m_iPaintLines - 2 ? m_iPaintLines - 2 : iDelta;
  794.         
  795.         if (!m_bDataSourceInWindow) // Springloading folders go haywire if we shift lines around, so don't do it
  796.             EnsureVisible( toggleIndex + iDelta );
  797.     }
  798.  
  799.     Invalidate();
  800. }
  801.  
  802. void CRDFOutliner::SelectItem(int iSel,int mode,UINT flags)
  803. {
  804.     int oldColumn = GetSelectedColumn();
  805.     
  806.     if (m_iColHit == -1)
  807.         return;
  808.  
  809.     UINT command = m_pColumn[ m_iColHit ]->iCommand;
  810.  
  811.     RemoveTextEdit();
  812.  
  813.     m_Node = HT_GetNthItem(m_View, iSel);
  814.  
  815.     if (!m_Node)
  816.     {
  817.         HT_SetSelectionAll(m_View, (PRBool)FALSE);
  818.         
  819.         if (mode != OUTLINER_RBUTTONDOWN)
  820.             return;
  821.  
  822.         m_Node = HT_TopNode(m_View);
  823.         iSel = -1;
  824.         
  825.     }
  826.  
  827.     switch (mode) 
  828.     {
  829.         case OUTLINER_RETURN:
  830.         case OUTLINER_LBUTTONDBLCLK:
  831.             OnSelDblClk(iSel);
  832.             m_bDoubleClick = TRUE;
  833.             if (m_hEditTimer)
  834.             {
  835.                 KillTimer(m_hEditTimer);
  836.                 m_hEditTimer = 0;
  837.             }
  838.             break;
  839.         case OUTLINER_LBUTTONUP:
  840.             if (m_bNeedToClear)
  841.             {
  842.                 HT_SetSelection(m_Node);
  843.                 if (m_bNeedToEdit && !m_bDoubleClick)
  844.                 {
  845.  
  846.                     CRDFCommandMap& map = m_Parent->GetColumnCommandMap(); 
  847.                     CRDFColumn* theColumn = (CRDFColumn*)(map.GetCommand(m_nSelectedColumn));
  848.         
  849.                     BOOL isEditable = HT_IsNodeDataEditable(m_Node, theColumn->GetToken(), 
  850.                                                             theColumn->GetDataType());
  851.  
  852.                     // Get down.... get down... time for a column edit.
  853.                     if (isEditable)
  854.                         m_hEditTimer = SetTimer(IDT_EDITFOCUS, EDIT_DELAY, NULL);
  855.                 }
  856.             }
  857.             m_bNeedToClear = FALSE;
  858.             m_bNeedToEdit = FALSE;
  859.             m_bDoubleClick = FALSE;
  860.             break;    
  861.         case OUTLINER_LBUTTONDOWN:
  862.         case OUTLINER_KEYDOWN:
  863.         case OUTLINER_SET:
  864.              m_iFocus = iSel;
  865.             m_bNeedToClear = FALSE;
  866.             m_bNeedToEdit = FALSE;
  867.             SetSelectedColumn((int)command);
  868.             
  869.             if (flags & MK_CONTROL) 
  870.             {
  871.                 // Causes a selection toggle.
  872.                 HT_ToggleSelection(m_Node);    
  873.             }
  874.             else if (flags & MK_SHIFT) 
  875.             {
  876.                 // A range of items is being selected.
  877.                 HT_Resource node = HT_GetNthItem(m_View, m_iSelection);
  878.                 if (node != NULL)
  879.                 {
  880.                     HT_SetSelectionRange(node, m_Node);
  881.                 }
  882.             }
  883.             else 
  884.             {
  885.                 m_iSelection = iSel;
  886.  
  887.                 if (!IsSelected(m_iFocus))
  888.                 {
  889.                     HT_SetSelection(m_Node);
  890.                     
  891.                     //if (!HT_IsContainer(m_Node) && !HT_IsSeparator(m_Node) && IsDocked())
  892.                     //    DisplayURL();  For now do double-click behavior
  893.                 }
  894.                 else 
  895.                 {
  896.                     m_bNeedToClear = TRUE;
  897.                     if (oldColumn == m_nSelectedColumn)
  898.                         m_bNeedToEdit = TRUE;
  899.                 }
  900.             }    
  901.             break;
  902.  
  903.         case OUTLINER_RBUTTONDOWN:
  904.              m_iFocus = iSel;
  905.             SetSelectedColumn((int)command);    
  906.             m_iSelection = iSel;
  907.  
  908.             if (m_iFocus >= 0 && !IsSelected(m_iFocus))
  909.             {
  910.                 HT_SetSelection(m_Node);
  911.             }    
  912.             break;
  913.         default:
  914.             break;
  915.     }
  916. }
  917.  
  918. BOOL CRDFOutliner::DeleteItem(int iSel)
  919. {
  920.     HT_DoMenuCmd(m_Pane, HT_CMD_CUT);
  921.     return TRUE;
  922. }
  923.  
  924. BOOL CRDFOutliner::IsDocked()
  925. {
  926.     CGenericFrame* theFrame = (CGenericFrame*)FEU_GetLastActiveFrame();
  927.     
  928.     if (theFrame == NULL)
  929.       return FALSE;
  930.  
  931.     return theFrame->IsChild(this);
  932. }
  933.  
  934. void CRDFOutliner::OnSelDblClk(int iLine)
  935. {
  936.     if (m_Node)
  937.     {
  938.         if (HT_IsContainer(m_Node))
  939.         {
  940.             ToggleExpansion(iLine);
  941.         }
  942.         else if (!HT_IsSeparator(m_Node))// && !IsDocked()) For now always do double-click behavior
  943.         {
  944.             DisplayURL();
  945.         }
  946.     }
  947. }
  948.  
  949. void CRDFOutliner::DisplayURL()
  950. {
  951.     char* url = HT_GetNodeURL(m_Node);
  952.     if (IsExecutableURL(url))
  953.     {
  954.         // Shell Execute
  955. #ifdef _WIN32
  956.         char* pLocalName = NULL;
  957.         XP_ConvertUrlToLocalFile(url, &pLocalName);
  958.         pLocalName = NET_UnEscape(pLocalName);
  959.  
  960.         SHELLEXECUTEINFO    sei;
  961.       
  962.         // Use ShellExecuteEx to launch
  963.         sei.cbSize = sizeof(sei);
  964.         sei.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_NOCLOSEPROCESS;
  965.         sei.hwnd = NULL;
  966.         sei.lpVerb = NULL;  // default to Open
  967.         sei.lpFile = pLocalName;
  968.         sei.lpParameters = NULL;
  969.         sei.lpDirectory = NULL;
  970.         sei.nShow = SW_SHOW;
  971.         ShellExecuteEx(&sei);
  972.         int uSpawn = (UINT)sei.hInstApp;
  973.         if(uSpawn <= 32)    
  974.         {
  975.             char szMsg[80];
  976.             switch(uSpawn) 
  977.             {
  978.                 case 0:
  979.                 case 8:
  980.                     sprintf(szMsg, szLoadString(IDS_WINEXEC_0_8));
  981.                     break;
  982.                 case 2:                                      
  983.                 case 3:
  984.                     sprintf(szMsg, szLoadString(IDS_WINEXEC_2_3));
  985.                     break;
  986.                 case 10:
  987.                 case 11:
  988.                 case 12:
  989.                 case 13:
  990.                 case 14:
  991.                 case 15:
  992.                     sprintf(szMsg, szLoadString(IDS_WINEXEC_10_THRU_15));
  993.                     break;
  994.                 case 16:
  995.                     sprintf(szMsg, szLoadString(IDS_WINEXEC_16));
  996.                     break;
  997.                 case 21:
  998.                     sprintf(szMsg, szLoadString(IDS_WINEXEC_21));
  999.                     break;
  1000.                 default:
  1001.                     sprintf(szMsg, szLoadString(IDS_WINEXEC_XX), uSpawn);
  1002.                     break;
  1003.             }        
  1004.         
  1005.             CString s;
  1006.             if (s.LoadString( IDS_BOOKMARK_ADDRESSPROPERTIES ))
  1007.             {
  1008.                 ::MessageBox(GetParentFrame()->m_hWnd, szMsg, s, MB_OK | MB_APPLMODAL);
  1009.             }
  1010.         }
  1011.         if (pLocalName)
  1012.             XP_FREE(pLocalName);
  1013. #endif // _WIN32
  1014.     }
  1015.     else
  1016.     {
  1017.         CAbstractCX * pCX = FEU_GetLastActiveFrameContext();
  1018.         ASSERT(pCX != NULL);
  1019.         if (pCX != NULL)
  1020.         {
  1021.             if (!strncmp(url, "nes:", 4)) 
  1022.               pCX->NormalGetUrl((LPTSTR)&url[4]);
  1023.             else 
  1024.               pCX->NormalGetUrl((LPTSTR) url);
  1025.         }
  1026.     }
  1027. }
  1028.  
  1029. BOOL CRDFOutliner::TestRowCol(POINT point, int &iRow, int &iCol)
  1030. {
  1031.     RECT rcClient;
  1032.     GetClientRect(&rcClient);
  1033.     BOOL answer = TRUE;
  1034.  
  1035.     if (::PtInRect(&rcClient, point)) 
  1036.     {
  1037.         void *pLineData = NULL;
  1038.         int iSel = point.y  / m_itemHeight;
  1039.         int iNewSel = m_iTopLine + iSel;
  1040.         if ( ( pLineData = AcquireLineData ( iNewSel ) ) != NULL ) 
  1041.         {
  1042.             ReleaseLineData( pLineData );
  1043.             iRow = iNewSel;
  1044.         }
  1045.         else answer = FALSE;
  1046.  
  1047.         int i, offset;
  1048.         int y = iSel * m_itemHeight;
  1049.  
  1050.         for ( i = 0, offset = 0; i < m_iVisColumns; i++ )
  1051.         {
  1052.            CRect rect ( offset, y,
  1053.                         offset + m_pColumn[ i ]->iCol, y + m_itemHeight );
  1054.  
  1055.            if ( rect.PtInRect(point) ) 
  1056.            {
  1057.                 iCol = i;
  1058.                 m_rcHit = rect;
  1059.                 return answer;
  1060.            }
  1061.                 
  1062.            offset += m_pColumn[ i ]->iCol;
  1063.         }
  1064.     }
  1065.     return FALSE;
  1066. }
  1067.  
  1068. int CRDFOutliner::DetermineClickLocation(CPoint point)
  1069. {
  1070.     // TestRowCol returns FALSE if the row clicked on contains no data. We must have clicked on the background
  1071.     // in this case.
  1072.     int iRow, iCol;
  1073.  
  1074.     if ( !TestRowCol( point, iRow, iCol ) )
  1075.         return CLICKED_BACKGROUND;
  1076.  
  1077.     // We clicked on a row/column with data.  Update our member variables to reflect our hit.
  1078.     m_iRowHit = iRow;
  1079.     m_iColHit = iCol;
  1080.  
  1081.     // Get the text rectangle corresponding to the hit column.
  1082.     CRect textRect = GetColumnRect(iRow, (int)(m_pColumn[iCol]->iCommand));
  1083.  
  1084.     // Double-check and make sure we have line data.  (We should, but let's be safe.)
  1085.     void * pLineData;
  1086.     if ( ( pLineData = AcquireLineData ( iRow ) ) == NULL)
  1087.         return CLICKED_BACKGROUND;
  1088.     int iDepth;
  1089.     GetTreeInfo ( iRow, NULL, &iDepth, NULL );
  1090.     HT_Resource r = (HT_Resource)pLineData;
  1091.     ReleaseLineData ( pLineData );
  1092.             
  1093.     // If the user clicked on the image column, they might have struck the trigger.  Check for this.
  1094.     if ( m_pColumn[ iCol ]->iCommand == m_idImageCol ) 
  1095.     {
  1096.         int iImageWidth = m_pIImage->GetImageWidth ( );
  1097.         RECT rcToggle = m_rcHit;
  1098.         rcToggle.left += iDepth * iImageWidth;
  1099.         rcToggle.right = rcToggle.left + iImageWidth;
  1100.  
  1101.         // If the data is a container and if the point is inside the toggle rect, the user clicked the
  1102.         // trigger.
  1103.         if ( ::PtInRect( &rcToggle, point ) && HT_IsContainer(r)) 
  1104.             return CLICKED_TRIGGER;
  1105.             
  1106.         // If the user clicked to the left of the trigger on a container, then treat as a background click.
  1107.         // If the user clicked where the trigger would have been (or to the left of the trigger) on a non-
  1108.         // container, then treat that as a background click also.
  1109.         if ((point.x < rcToggle.left && HT_IsContainer(r)) ||
  1110.             (point.x < rcToggle.right && !HT_IsContainer(r)))
  1111.           return CLICKED_BACKGROUND;
  1112.     }
  1113.  
  1114.     // See if the user clicked on the column text. 
  1115.     const char* text = GetColumnText(m_pColumn[ iCol ]->iCommand, r);
  1116.     if (!text)
  1117.         return CLICKED_BACKGROUND;  // Column has no text. User has to have clicked on the background.
  1118.  
  1119.     // All this code just determines our text rectangle.
  1120.     CClientDC dc(this);
  1121.     CString theString(text);
  1122.     CRect bgRect;
  1123.     dc.SelectObject( GetLineFont( r ) );
  1124.     UINT dwDTFormat = DT_NOCLIP | DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER;
  1125.     switch (m_pColumn[ iCol ]->alignment) 
  1126.     {
  1127.         case AlignCenter:
  1128.             dwDTFormat |= DT_CENTER;
  1129.             break;
  1130.         case AlignRight:
  1131.             dwDTFormat |= DT_RIGHT;
  1132.             break;
  1133.         case AlignLeft:
  1134.         default:
  1135.             dwDTFormat |= DT_LEFT;
  1136.     }
  1137.         
  1138.     dc.DrawText(theString, theString.GetLength(), &bgRect, DT_CALCRECT | dwDTFormat);
  1139.     int w = bgRect.Width() + 2*COL_LEFT_MARGIN;
  1140.     if (w > textRect.Width())
  1141.         w = textRect.Width();
  1142.     bgRect.left = textRect.left;
  1143.     bgRect.top = textRect.top;
  1144.     bgRect.right = bgRect.left + w;
  1145.     bgRect.bottom = textRect.bottom;
  1146.         
  1147.     if ( m_pColumn[ iCol ]->iCommand == m_idImageCol ) 
  1148.       bgRect.left -= (m_pIUserImage->GetImageWidth() + OUTLINE_TEXT_OFFSET);
  1149.  
  1150.     // Now that we've set up the rect, see if the user clicked in it.  If they didn't, it's a background
  1151.     // click.
  1152.     if (!bgRect.PtInRect(point))
  1153.         return CLICKED_BACKGROUND;
  1154.         
  1155.     // User jumped through all our hoops.  Must have clicked on some actual data.  
  1156.     return CLICKED_LINE;
  1157. }
  1158.  
  1159. void CRDFOutliner::OnLButtonDown ( UINT nFlags, CPoint point )
  1160. {
  1161. // Reset drag rect info
  1162.     m_bCheckForDragRect = FALSE;
  1163.     m_LastDragRect = CRect(0,0,0,0);
  1164.     m_nRectYDisplacement = 0;
  1165.  
  1166.     Default();
  1167.     TipHide();
  1168.  
  1169.     SetFocus();
  1170.  
  1171.     m_ptHit = point;
  1172.     
  1173.     m_iRowHit = -1;
  1174.     m_iColHit = -1;
  1175.     
  1176.     int clickResult = DetermineClickLocation(point);
  1177.     
  1178.     if (clickResult == CLICKED_TRIGGER)
  1179.         DoToggleExpansion(m_iRowHit);
  1180.     else if (clickResult == CLICKED_LINE)                
  1181.     {
  1182.         if ( ColumnCommand( m_pColumn[ m_iColHit ]->iCommand, m_iRowHit) )
  1183.             return;
  1184.  
  1185.         SetCapture();
  1186.         
  1187.         SelectItem( m_iRowHit, OUTLINER_LBUTTONDOWN, nFlags );
  1188.     }
  1189.     else
  1190.     {
  1191.         // user clicked on the background
  1192.         m_bCheckForDragRect = TRUE;
  1193.         SetCapture();
  1194.         m_iFocus = -1;
  1195.         if (m_iColHit != -1)
  1196.         {
  1197.             SetSelectedColumn(m_pColumn[ m_iColHit ]->iCommand);
  1198.         }
  1199.         HT_SetSelectionAll(m_View, (PRBool)FALSE);
  1200.     }
  1201. }
  1202.  
  1203. void CRDFOutliner::OnLButtonUp(UINT nFlags, CPoint point)
  1204. {
  1205.     if (GetCapture() == this) {
  1206.         ReleaseCapture();
  1207.         if (m_LastDragRect != CRect(0,0,0,0))
  1208.         {
  1209.             // Dragging happened
  1210.             CClientDC dc(this);
  1211.             EraseDragRect(&dc, m_LastDragRect);
  1212.  
  1213.             if (m_hDragRectTimer)
  1214.             {
  1215.                 KillTimer(m_hDragRectTimer);
  1216.                 m_hDragRectTimer = 0;
  1217.             }
  1218.         }
  1219.         else SelectItem( m_iSelection, OUTLINER_LBUTTONUP, nFlags );
  1220.     }
  1221. }
  1222.  
  1223. void CRDFOutliner::OnRButtonDown ( UINT nFlags, CPoint point )
  1224. {
  1225.     // Update our column hit, since we draw selected columns.
  1226.     m_iRowHit = -1;
  1227.     m_iColHit = -1;
  1228.  
  1229.     int clickResult = DetermineClickLocation(point);
  1230.     
  1231.     if (clickResult == CLICKED_LINE)                
  1232.     {
  1233.         // user clicked on the item.  We will go ahead and select.
  1234.         SelectItem( m_iRowHit, OUTLINER_RBUTTONDOWN, nFlags );
  1235.     }
  1236.     else
  1237.     {
  1238.         // user clicked on the background... deselect everything.        
  1239.         m_iFocus = -1;
  1240.         HT_SetSelectionAll(m_View, (PRBool)FALSE);
  1241.     }
  1242.  
  1243. /*
  1244.     int iRow, iCol;
  1245.     if ( TestRowCol( point, iRow, iCol ) ){
  1246.         HT_Resource pEntry = HT_GetNthItem(m_View, iRow);
  1247.         CExportRDF exportDlg;
  1248.  
  1249.         if (exportDlg.DoModal() == IDOK) {
  1250.             FILE* mcfStr;
  1251.             mcfStr = fopen(exportDlg.m_csAns, "w");
  1252.             outputMCFTree(RDF_GetNavCenterDB(), stdPrint, mcfStr, HT_GetRDFResource(pEntry));
  1253.             fclose(mcfStr);  
  1254.         }
  1255.     }
  1256.     */
  1257. }
  1258.  
  1259. void CRDFOutliner::OnRButtonUp( UINT nFlags, CPoint point )
  1260. {
  1261.     m_ptHit = point;
  1262.     int iSel = m_iTopLine + (point.y  / m_itemHeight);
  1263.     
  1264.     int clickResult = DetermineClickLocation(point);
  1265.     PropertyMenu( iSel, clickResult );
  1266. }
  1267.  
  1268. void CRDFOutliner::DragRectScroll( BOOL bBackwards )
  1269. {
  1270.     int oldLine = m_iTopLine;
  1271.     OnVScroll(bBackwards ? SB_LINEUP : SB_LINEDOWN, 0, 0);
  1272.     m_nRectYDisplacement += (oldLine - m_iTopLine)*m_itemHeight;
  1273.     if (m_nRectYDisplacement != 0)
  1274.     {
  1275.         OnMouseMove(0, m_MovePoint);
  1276.     }
  1277. }
  1278.  
  1279. CRect CRDFOutliner::ConstructDragRect(const CPoint& pt1, const CPoint& pt2)
  1280. {
  1281.     int left = pt1.x < pt2.x ? pt1.x : pt2.x;
  1282.     int right = pt1.x > pt2.x ? pt1.x : pt2.x;
  1283.  
  1284.     int top = pt1.y < pt2.y ? pt1.y : pt2.y;
  1285.     int bottom = pt1.y > pt2.y ? pt1.y : pt2.y;
  1286.  
  1287.     return CRect(left, top, right, bottom);
  1288. }
  1289.  
  1290. void CRDFOutliner::EraseDragRect(CDC* pDC, CRect rect)
  1291. {
  1292. #ifdef XP_WIN32
  1293.     CRgn rgnLast, rgnOutside, rgnInside;
  1294.  
  1295.     // set up regions and rects for drag rect with border of size (1,1)
  1296.     rgnLast.CreateRectRgn(0, 0, 0, 0);
  1297.     rgnOutside.CreateRectRgnIndirect(&rect);
  1298.     CRect rect2 = rect;
  1299.     rect.InflateRect(-1, -1);
  1300.     rect.IntersectRect(rect, rect2);
  1301.     rgnInside.CreateRectRgnIndirect(&rect);
  1302.     rgnLast.CombineRgn(&rgnOutside, &rgnInside, RGN_XOR);
  1303.  
  1304.     // Do the erase
  1305.     pDC->SelectClipRgn(&rgnLast);
  1306.     pDC->GetClipBox(&rect);
  1307.     CBrush* pBrushLast = CDC::GetHalftoneBrush();
  1308.     CBrush* pBrushOld = pDC->SelectObject(pBrushLast);
  1309.     pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATINVERT);
  1310.     pDC->SelectObject(pBrushOld);
  1311.     pDC->SelectClipRgn(NULL);
  1312. #endif
  1313. }
  1314.  
  1315. void CRDFOutliner::OnMouseMove(UINT nFlags, CPoint point)
  1316. {
  1317.     if (GetCapture() == this) 
  1318.     {
  1319. #ifdef XP_WIN32
  1320.         if (m_bCheckForDragRect)
  1321.         {
  1322.             CRect rect;
  1323.             GetClientRect(&rect);
  1324.  
  1325.             // We're dragging a rectangle, baby.
  1326.             if (point.x < 0) // HACK so hit test works
  1327.                 point.x = 0;
  1328.  
  1329.             if (point.y < 0)
  1330.                 point.y = 0;
  1331.  
  1332.             if (point.y > rect.bottom)
  1333.                 point.y = rect.bottom;
  1334.             
  1335.             m_MovePoint = point;
  1336.  
  1337.             if ( point.y < m_itemHeight ) 
  1338.             {
  1339.                 m_hDragRectTimer = SetTimer(IDT_DRAGRECT, GetDragHeartbeat(), NULL);
  1340.             } 
  1341.             else if ( point.y > (rect.bottom - m_itemHeight) ) 
  1342.             {
  1343.                 m_hDragRectTimer = SetTimer(IDT_DRAGRECT, GetDragHeartbeat(), NULL);
  1344.             }
  1345.             else if (m_hDragRectTimer)
  1346.             {
  1347.                 KillTimer(m_hDragRectTimer);
  1348.                 m_hDragRectTimer = 0;
  1349.             }
  1350.             
  1351.             CClientDC dc(this);
  1352.             CRect newRect = ConstructDragRect(m_ptHit, point);
  1353.  
  1354.             // Determine the new selection state
  1355.             if (m_LastDragRect == CRect(0,0,0,0))
  1356.                 dc.DrawDragRect(&newRect, CSize(1,1), NULL, CSize(1,1));
  1357.             else 
  1358.             {
  1359.                 // Displace the rects to account for scrolling
  1360.                 m_LastDragRect.OffsetRect(0, m_nRectYDisplacement);
  1361.                 newRect.OffsetRect(0, m_nRectYDisplacement);
  1362.  
  1363.                 if (m_nRectYDisplacement > 0)
  1364.                     newRect.top += m_nRectYDisplacement;
  1365.                 else newRect.bottom -= m_nRectYDisplacement;
  1366.  
  1367.                 // Reset the displacement for future scroll events
  1368.                 m_nRectYDisplacement = 0;
  1369.                 
  1370.                 // Potential to add selection.
  1371.                 CPoint testPoint1 = m_LastDragRect.TopLeft();
  1372.                 CPoint testPoint2 = newRect.TopLeft();
  1373.                 if (m_LastDragRect.bottom != newRect.bottom)
  1374.                 {
  1375.                     testPoint1 = CPoint(m_LastDragRect.left, 
  1376.                                         m_LastDragRect.bottom);
  1377.                     testPoint2 = CPoint(newRect.left, newRect.bottom);
  1378.                 }
  1379.                 int iRow = -1;
  1380.                 int iCol = -1;
  1381.                 int otherRow = -1;
  1382.                 int otherCol = -1;
  1383.                 TestRowCol(testPoint1, iRow, iCol);
  1384.                 TestRowCol(testPoint2, otherRow, otherCol);
  1385.  
  1386.                 // Both over selections.
  1387.                 if (iRow != otherRow)
  1388.                 {
  1389.                     // Erase the old drag rect
  1390.                     EraseDragRect(&dc, m_LastDragRect);
  1391.                     UpdateWindow();
  1392.  
  1393.                     // Add or remove selection...
  1394.                     int start;
  1395.                     int end;
  1396.                     BOOL select;
  1397.  
  1398.                     if (iRow == -1)
  1399.                         iRow = otherRow+1;
  1400.                     else if (otherRow == -1)
  1401.                         otherRow = iRow+1;
  1402.  
  1403.                     if (m_LastDragRect.bottom < newRect.bottom)
  1404.                     {
  1405.                         start = iRow+1;
  1406.                         end = otherRow+1;
  1407.                         select = TRUE;
  1408.                     }
  1409.                     else if (m_LastDragRect.bottom > newRect.bottom)
  1410.                     {
  1411.                         start = otherRow+1;
  1412.                         end = iRow+1;
  1413.                         select = FALSE;
  1414.                     }
  1415.                     else if (m_LastDragRect.top > newRect.top)
  1416.                     {
  1417.                         start = otherRow;
  1418.                         end = iRow;
  1419.                         select = TRUE;
  1420.                     }
  1421.                     else if (m_LastDragRect.top < newRect.top)
  1422.                     {
  1423.                         start = iRow;
  1424.                         end = otherRow;
  1425.                         select = FALSE;
  1426.                     }
  1427.  
  1428.                     // Going from start to end, performing selection
  1429.                     for (int i = start; i < end; i++)
  1430.                     {
  1431.                         HT_Resource r = HT_GetNthItem(m_View, i);
  1432.                         if (r)
  1433.                             HT_SetSelectedState(r, (PRBool)select);
  1434.                     }
  1435.  
  1436.                     UpdateWindow();
  1437.  
  1438.                     // Draw the new rect
  1439.                     dc.DrawDragRect(&newRect, CSize(1,1), NULL, CSize(1,1));
  1440.             
  1441.                 }
  1442.                 else 
  1443.                     dc.DrawDragRect(&newRect, CSize(1,1), &m_LastDragRect, CSize(1,1));
  1444.                 
  1445.             }
  1446.             m_LastDragRect = newRect;
  1447.         }
  1448.         else
  1449. #endif // XP_WIN32
  1450.  
  1451.         // See if the mouse has moved far enough to start
  1452.         // a drag operation
  1453.         if ((abs(point.x - m_ptHit.x) > 3)
  1454.         || (abs(point.y - m_ptHit.y) > 3)) 
  1455.         {
  1456.             // release the mouse capture
  1457.  
  1458.             ReleaseCapture();
  1459.             InitiateDragDrop();
  1460.  
  1461.             m_bClearOnRelease = FALSE;
  1462.             m_bSelectOnRelease = FALSE;
  1463.             SelectItem( m_iSelection, OUTLINER_LBUTTONUP, nFlags );
  1464.         }
  1465.     }
  1466.     if (m_iTipState != TIP_SHOWING)
  1467.         m_iTipState = TIP_WAITING;
  1468.     HandleMouseMove( point );
  1469. }
  1470.  
  1471.  
  1472. void CRDFOutliner::PropertyMenu(int iLine, UINT flags)
  1473. {
  1474. // Grab the resource
  1475.     BOOL backgroundCommands = (flags == CLICKED_BACKGROUND);
  1476.  
  1477.     CMenu popup;
  1478.     if (popup.CreatePopupMenu() != 0)
  1479.     {
  1480.         // We have a node and a menu. Fetch those commands.
  1481.         // Remove the elements from the last property menu we pulled up.
  1482.         m_MenuCommandMap.Clear();
  1483.         HT_Cursor theCursor = HT_NewContextualMenuCursor(m_View, (PRBool)FALSE, (PRBool)backgroundCommands);
  1484.         if (theCursor != NULL)
  1485.         {
  1486.             // We have a cursor. Attempt to iterate
  1487.             HT_MenuCmd theCommand; 
  1488.             while (HT_NextContextMenuItem(theCursor, &theCommand))
  1489.             {
  1490.                 char* menuName = HT_GetMenuCmdName(theCommand);
  1491.                 if (theCommand == HT_CMD_SEPARATOR)
  1492.                     popup.AppendMenu(MF_SEPARATOR);
  1493.                 else
  1494.                 {
  1495.                     // Add the command to our command map
  1496.                     CRDFMenuCommand* rdfCommand = new CRDFMenuCommand(menuName, theCommand);
  1497.                     int index = m_MenuCommandMap.AddCommand(rdfCommand);
  1498.                     popup.AppendMenu(MF_ENABLED, index+FIRST_HT_MENU_ID, menuName);
  1499.                 }
  1500.             }
  1501.             HT_DeleteCursor(theCursor);
  1502.         }
  1503.  
  1504.         //    Track the popup now.
  1505.         POINT pt = m_ptHit;
  1506.         ClientToScreen(&pt);
  1507.         popup.TrackPopupMenu( TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, this, NULL );
  1508.  
  1509.         //  Cleanup
  1510.         popup.DestroyMenu();
  1511.     }
  1512. }
  1513.  
  1514. BOOL CRDFOutliner::OnCommand(UINT wParam, LONG lParam)
  1515. {
  1516.     if (wParam >= FIRST_HT_MENU_ID && wParam <= LAST_HT_MENU_ID)
  1517.     {
  1518.         // A selection was made from the context menu.
  1519.         // Use the menu map to get the HT command value
  1520.         CRDFMenuCommand* theCommand = (CRDFMenuCommand*)(m_MenuCommandMap.GetCommand((int)wParam-FIRST_HT_MENU_ID));
  1521.         if (theCommand)
  1522.         {
  1523.             HT_MenuCmd htCommand = theCommand->GetHTCommand();
  1524.             HT_DoMenuCmd(m_Pane, htCommand);
  1525.         }
  1526.     }
  1527.  
  1528.     return TRUE;
  1529. }
  1530.  
  1531. void CRDFOutliner::OnSetFocus ( CWnd * pOldWnd )
  1532. {
  1533.     // Update the context's stored RDF Info.  Hack for the back end.  Needs to go away eventually.
  1534.     theApp.m_pRDFCX->TrackRDFWindow(this);
  1535.     
  1536.     Default();
  1537.  
  1538.     if (m_iSelection >= 0)
  1539.         for (int i =0; i < (m_iTopLine+m_iPaintLines); i++)
  1540.             if (IsSelected(i))
  1541.                 InvalidateLine(i);
  1542.     
  1543.     FocusCheck(pOldWnd, TRUE);
  1544. }
  1545.     
  1546. void CRDFOutliner::OnKillFocus ( CWnd * pNewWnd )
  1547. {
  1548.     CWnd::OnKillFocus ( pNewWnd );
  1549.     if (m_iSelection >= 0)
  1550.         for (int i =0; i < (m_iTopLine+m_iPaintLines); i++)
  1551.             if (IsSelected(i))
  1552.                 InvalidateLine(i);
  1553.  
  1554.     ((COutlinerParent*)GetParent())->UpdateFocusFrame();
  1555.  
  1556.     FocusCheck(pNewWnd, FALSE);
  1557. }
  1558.     
  1559. void CRDFOutliner::FocusCheck(CWnd* pWnd, BOOL gotFocus)
  1560. {
  1561.     if (m_NavMenuBar)
  1562.     {
  1563.         if (gotFocus)
  1564.             m_NavMenuBar->NotifyFocus(TRUE);
  1565.         else
  1566.         {
  1567.             CFrameWnd* pFrame = GetParentFrame();
  1568.             if (pFrame && !pFrame->IsChild(pWnd))
  1569.             {
  1570.                 // Invalidate for a redraw
  1571.                 m_NavMenuBar->NotifyFocus(FALSE);
  1572.             }
  1573.         }
  1574.     }
  1575. }
  1576.  
  1577. COLORREF Darken(COLORREF r)
  1578. {
  1579.     COLORREF ref = GetSysColor(COLOR_WINDOW);
  1580.     float x = GetRValue(ref);
  1581.     float y = GetGValue(ref);
  1582.     float z = GetBValue(ref);
  1583.     
  1584.     x = 0.75f*(x+1);
  1585.     y = 0.75f*(y+1);
  1586.     z = 0.75f*(z+1);
  1587.  
  1588.     BYTE newR = (BYTE)(int)x;
  1589.     BYTE newG = (BYTE)(int)y;
  1590.     BYTE newB = (BYTE)(int)z;
  1591.  
  1592.     return RGB(newR, newG, newB);
  1593. }
  1594.  
  1595. COLORREF Brighten(COLORREF r)
  1596. {
  1597.     COLORREF ref = GetSysColor(COLOR_WINDOW);
  1598.     float x = GetRValue(ref);
  1599.     float y = GetGValue(ref);
  1600.     float z = GetBValue(ref);
  1601.     
  1602.     x = x + 0.25f*(256 - x);
  1603.     y = y + 0.25f*(256 - y);
  1604.     z = z + 0.25f*(256 - z);
  1605.  
  1606.     if (x > 255.0f) x = 255.0f;
  1607.     if (y > 255.0f) y = 255.0f;
  1608.     if (z > 255.0f) z = 255.0f;
  1609.  
  1610.     BYTE newR = (BYTE)(int)x;
  1611.     BYTE newG = (BYTE)(int)y;
  1612.     BYTE newB = (BYTE)(int)z;
  1613.  
  1614.     return RGB(newR, newG, newB);
  1615. }
  1616.  
  1617. void CRDFOutliner::OnPaint()
  1618. {
  1619.     m_bPaintingFirstObject = TRUE;
  1620.  
  1621.     RECT rcClient;
  1622.     GetClientRect(&rcClient);
  1623.     CPaintDC pdc ( this );
  1624.  
  1625.     COLORREF bgColor = GetSysColor(COLOR_WINDOW);
  1626.     COLORREF textColor = GetSysColor(COLOR_WINDOWTEXT);
  1627.     COLORREF sortColor;
  1628.     if (GetRValue(bgColor) == 255 && GetGValue(bgColor) == 255 && GetBValue(bgColor) == 255 
  1629.         && sysInfo.m_iBitsPerPixel > 8)
  1630.     {
  1631.             // Translate white to gray (HACK TO SATISFY THE MIGHTY GUHA)
  1632.             sortColor = RGB(192,192,192);
  1633.             bgColor = RGB(224,224,224);
  1634.             textColor = RGB(0,0,0);
  1635.     }
  1636.     else
  1637.     {
  1638.         if (((GetRValue(textColor) + GetGValue(textColor) + GetBValue(textColor))/3) > 128)
  1639.             sortColor = Darken(bgColor);
  1640.         else sortColor = Brighten(bgColor);
  1641.     }
  1642.  
  1643.     HPALETTE hPalette = WFE_GetUIPalette(GetParentFrame());
  1644.     HPALETTE pOldPalette = ::SelectPalette(pdc.m_hDC, hPalette, TRUE);    
  1645. /*
  1646.     if (sysInfo.m_iBitsPerPixel <= 8)
  1647.     {
  1648.         PALETTEENTRY paletteColors[1];
  1649.             
  1650.         UINT index;
  1651.  
  1652.         index = ::GetNearestPaletteIndex(hPalette, sortColor);
  1653.         ::GetPaletteEntries(hPalette, index, 1, paletteColors);
  1654.         sortColor = RGB(paletteColors[0].peRed, paletteColors[0].peGreen, paletteColors[0].peBlue);
  1655.  
  1656.         index = ::GetNearestPaletteIndex(hPalette, bgColor);
  1657.         ::GetPaletteEntries(hPalette, index, 1, paletteColors);
  1658.         bgColor = RGB(paletteColors[0].peRed, paletteColors[0].peGreen, paletteColors[0].peBlue);
  1659.  
  1660.         index = ::GetNearestPaletteIndex(hPalette, textColor);
  1661.         ::GetPaletteEntries(hPalette, index, 1, paletteColors);
  1662.         textColor = RGB(paletteColors[0].peRed, paletteColors[0].peGreen, paletteColors[0].peBlue);
  1663.     }
  1664. */
  1665.     HBRUSH hRegBrush = (HBRUSH) ::CreateSolidBrush(bgColor); 
  1666.     HPEN hRegPen = (HPEN)::CreatePen( PS_SOLID, 0, bgColor);
  1667.  
  1668.     HBRUSH hHighBrush = ::CreateSolidBrush( GetSysColor( COLOR_HIGHLIGHT ) );
  1669.     HPEN hHighPen = ::CreatePen( PS_SOLID, 0, GetSysColor ( COLOR_HIGHLIGHT ) );
  1670.  
  1671.     HBRUSH hOldBrush = (HBRUSH) pdc.SelectObject ( hRegBrush );
  1672.     HPEN hOldPen = (HPEN) pdc.SelectObject ( hRegPen );
  1673.     COLORREF cOldText = pdc.SetTextColor ( textColor );
  1674.     COLORREF cOldBk = pdc.SetBkColor ( bgColor );
  1675.  
  1676.     int i;            
  1677.     for ( i = pdc.m_ps.rcPaint.top / m_itemHeight; 
  1678.         i < ( pdc.m_ps.rcPaint.bottom / m_itemHeight ) + 1; i++ ) 
  1679.     {
  1680.  
  1681.         int index = i + m_iTopLine;
  1682.  
  1683.         PaintLine ( i, pdc.m_hDC, &pdc.m_ps.rcPaint, sortColor, hHighBrush, hHighPen );
  1684.  
  1685.         if (m_bPaintingFirstObject)
  1686.             m_bPaintingFirstObject = FALSE;
  1687.     }
  1688.  
  1689.     pdc.SetTextColor ( cOldText );
  1690.     pdc.SetBkColor ( cOldBk );        
  1691.     pdc.SelectObject ( hOldPen );
  1692.     pdc.SelectObject ( hOldBrush );
  1693.     
  1694.     ::SelectPalette(pdc.m_hDC, pOldPalette, FALSE);
  1695.  
  1696.     VERIFY(DeleteObject( hRegBrush ));
  1697.     VERIFY(DeleteObject( hRegPen ));
  1698.     VERIFY(DeleteObject( hHighBrush ));
  1699.     VERIFY(DeleteObject( hHighPen ));
  1700. }
  1701.  
  1702. void CRDFOutliner::PaintLine ( int iLineNo, HDC hdc, LPRECT lpPaintRect, COLORREF sortColor,
  1703.                                HBRUSH hHighlightBrush,
  1704.                                HPEN hHighlightPen )
  1705. {
  1706.     void * pLineData;
  1707.     int iImageWidth = m_pIImage->GetImageWidth ( );
  1708.     CRect WinRect;
  1709.     GetClientRect(&WinRect);
  1710.  
  1711.     int y = m_itemHeight * iLineNo;
  1712.  
  1713.     int iColumn, offset;
  1714.     CRect rectColumn, rectInter;
  1715.  
  1716.     rectColumn.top = y;
  1717.     rectColumn.bottom = y + m_itemHeight;
  1718.  
  1719.     if ( !( pLineData = AcquireLineData( iLineNo + m_iTopLine )) ) 
  1720.     {
  1721.         EraseLine ( iLineNo, hdc, lpPaintRect );
  1722.         if (ViewerHasFocus() && HasFocus(iLineNo + m_iTopLine)) 
  1723.         {
  1724.             rectColumn.left = WinRect.left;
  1725.             rectColumn.right = WinRect.right;
  1726.             DrawFocusRect ( hdc, &rectColumn );
  1727.         }
  1728.  
  1729.         // Draw the column rect
  1730.         for ( int iColumn = offset = 0; iColumn < m_iVisColumns; iColumn++ )
  1731.         {
  1732.             rectColumn.left = offset;
  1733.             rectColumn.right = offset + m_pColumn[ iColumn ]->iCol;
  1734.  
  1735.             if (iColumn == GetSortColumn())
  1736.             {
  1737.                 // Draw the sort rect (Yes, I know this is inefficient.)
  1738.                 HBRUSH hSortBrush = (HBRUSH)::CreateSolidBrush(sortColor);
  1739.                 HBRUSH pOldBrush = (HBRUSH) ::SelectObject(hdc, hSortBrush);
  1740.                 ::FillRect(hdc, &rectColumn, (HBRUSH) GetCurrentObject(hdc, OBJ_BRUSH));
  1741.                 ::SelectObject(hdc, pOldBrush);
  1742.                 VERIFY(DeleteObject(hSortBrush));
  1743.             }
  1744.  
  1745.             offset += m_pColumn[ iColumn ]->iCol;
  1746.         }
  1747.         return;
  1748.     }
  1749.  
  1750.     HFONT hOldFont =(HFONT) ::SelectObject ( hdc, GetLineFont ( pLineData ) );
  1751.  
  1752.     for ( iColumn = offset = 0; iColumn < m_iVisColumns; iColumn++ )
  1753.     {
  1754.         rectColumn.left = offset;
  1755.         rectColumn.right = offset + m_pColumn[ iColumn ]->iCol;
  1756.  
  1757.         if ( rectInter.IntersectRect ( &rectColumn, lpPaintRect ) ) 
  1758.         {
  1759.             HBRUSH pOldBrush; 
  1760.             COLORREF cOldBk;
  1761.             HPEN pOldPen;
  1762.             HPEN hRegPen;
  1763.             HBRUSH hSortBrush;
  1764.             if (iColumn == GetSortColumn())
  1765.             {
  1766.                 hSortBrush = (HBRUSH)::CreateSolidBrush(sortColor);
  1767.                 pOldBrush = (HBRUSH) ::SelectObject(hdc, hSortBrush);
  1768.                 cOldBk = ::SetBkColor ( hdc, sortColor );
  1769.                 hRegPen = (HPEN)::CreatePen( PS_SOLID, 0, sortColor);
  1770.                 pOldPen = (HPEN)::SelectObject(hdc, hRegPen);
  1771.             }
  1772.  
  1773.             ::FillRect(hdc, &rectColumn, (HBRUSH) GetCurrentObject(hdc, OBJ_BRUSH));
  1774.             
  1775.             if ( m_pColumn[ iColumn ]->iCommand == m_idImageCol ) 
  1776.             {
  1777.                 rectColumn.left = DrawPipes ( iLineNo, iColumn, offset, hdc, pLineData );
  1778.                 rectColumn.left += OUTLINE_TEXT_OFFSET;
  1779.             }
  1780.             PaintColumn ( iLineNo, iColumn, rectColumn, hdc, pLineData, hHighlightBrush,
  1781.                           hHighlightPen );
  1782.  
  1783.             if (iColumn == GetSortColumn())
  1784.             {
  1785.                 ::SelectObject(hdc, pOldBrush);
  1786.                 ::SetBkColor(hdc, cOldBk);
  1787.                 ::SelectObject(hdc, pOldPen);
  1788.                 VERIFY(DeleteObject(hRegPen));
  1789.                 VERIFY(DeleteObject(hSortBrush));
  1790.             }
  1791.         }
  1792.  
  1793.         offset += m_pColumn[ iColumn ]->iCol;
  1794.     }
  1795.  
  1796.     rectColumn.left = offset;
  1797.     rectColumn.right = WinRect.right;
  1798.  
  1799.     ::FillRect(hdc, &rectColumn, (HBRUSH) GetCurrentObject(hdc, OBJ_BRUSH));
  1800.     PaintColumn ( iLineNo, iColumn, rectColumn, hdc, pLineData, hHighlightBrush, hHighlightPen );
  1801.  
  1802.     rectColumn.left = WinRect.left;
  1803.     rectColumn.right = WinRect.right;
  1804.  
  1805.     // if we are dragging we and we don't highlight we need to draw the drag line
  1806.     if(m_iDragSelection == m_iTopLine + iLineNo && !HighlightIfDragging() && GetSortColumn() == -1
  1807.         && m_iCurrentDropAction != DROPEFFECT_NONE)
  1808.        PaintDragLine(hdc, rectColumn);
  1809.  
  1810.     ::SelectObject ( hdc, hOldFont );
  1811.     ReleaseLineData ( pLineData );
  1812. }
  1813.  
  1814. void CRDFOutliner::PaintColumn(int iLineNo, int iColumn, LPRECT lpColumnRect, 
  1815.                                HDC hdc, void * pLineData, HBRUSH hHighlightBrush,
  1816.                                HPEN hHighlightPen)
  1817. {
  1818.     if (iColumn < m_iVisColumns) 
  1819.     {
  1820.         const char* lpsz = GetColumnText (m_pColumn[ iColumn ]->iCommand,pLineData);
  1821.         HT_Resource theNode = (HT_Resource)pLineData;
  1822.         if (theNode && HT_IsSeparator(theNode))
  1823.         {
  1824.             // Alter the column text name.
  1825.             lpsz = NULL;
  1826.         }
  1827.  
  1828.         if ( !RenderData( m_pColumn[iColumn]->iCommand, CRect(lpColumnRect), 
  1829.                           *CDC::FromHandle( hdc ), lpsz) ) 
  1830.         {
  1831.             BOOL hasFocus = FALSE;
  1832.         
  1833.             if (theNode && HT_IsSeparator(theNode))
  1834.             {
  1835.                 // Draw the horizontal line.
  1836.                 CPen separatorPen;
  1837.                 separatorPen.CreatePen(PS_SOLID, 1, GetSysColor ( COLOR_WINDOWTEXT ));
  1838.                 
  1839.                 HPEN sepPen = (HPEN)separatorPen.GetSafeHandle();
  1840.                 
  1841.                 HPEN usePen = IsSelected(iLineNo) ? hHighlightPen : sepPen;
  1842.  
  1843.                 HPEN pOldPen = (HPEN)(::SelectObject(hdc, usePen)); //separatorPen.GetSafeHandle()));
  1844.                 ::MoveToEx(hdc, lpColumnRect->left, lpColumnRect->top+m_itemHeight/2, NULL);
  1845.                 ::LineTo(hdc, lpColumnRect->right, lpColumnRect->top+m_itemHeight/2);
  1846.                 ::SelectObject(hdc, pOldPen);
  1847.             }
  1848.  
  1849.             if (lpsz) 
  1850.             {
  1851.                 if ((IsSelected(iLineNo + m_iTopLine) || 
  1852.                     ((m_iDragSelection == m_iTopLine + iLineNo) && HighlightIfDragging())) &&
  1853.                     IsSelectedColumn(iColumn))
  1854.                 {
  1855.                     hasFocus = HasFocus(iLineNo + m_iTopLine);
  1856.                     
  1857.                     if (ViewerHasFocus())
  1858.                     {
  1859.                         HBRUSH pOldBrush = (HBRUSH)(::SelectObject ( hdc, hHighlightBrush ));
  1860.                         HPEN pOldPen = (HPEN)(::SelectObject ( hdc, hHighlightPen ));
  1861.                         COLORREF cOldText = ::SetTextColor ( hdc, GetSysColor ( COLOR_HIGHLIGHTTEXT ) );
  1862.                         COLORREF oldColor = ::SetBkColor ( hdc, GetSysColor ( COLOR_HIGHLIGHT ) );
  1863.                         DrawColumn ( hdc, lpColumnRect, lpsz, 
  1864.                                  m_pColumn[ iColumn ]->cropping, 
  1865.                                  m_pColumn[ iColumn ]->alignment, hHighlightBrush, hasFocus );
  1866.                         ::SelectObject(hdc, pOldBrush);
  1867.                         ::SelectObject(hdc, pOldPen);
  1868.                         ::SetTextColor ( hdc, cOldText );
  1869.                         ::SetBkColor ( hdc, oldColor );
  1870.  
  1871.                     }
  1872.                     else DrawColumn ( hdc, lpColumnRect, lpsz, 
  1873.                                  m_pColumn[ iColumn ]->cropping, 
  1874.                                  m_pColumn[ iColumn ]->alignment, hHighlightBrush, hasFocus );
  1875.                 }
  1876.                 else DrawColumn ( hdc, lpColumnRect, lpsz, 
  1877.                                  m_pColumn[ iColumn ]->cropping, 
  1878.                                  m_pColumn[ iColumn ]->alignment);
  1879.  
  1880.             }
  1881.         }
  1882.     }
  1883. }
  1884.  
  1885. void CRDFOutliner::DrawColumn(HDC hdc, LPRECT lpColumnRect, LPCTSTR lpszString,
  1886.                               CropType_t cropping, AlignType_t alignment, HBRUSH theBrush,
  1887.                               BOOL hasFocus)
  1888. {
  1889.     if (!(lpColumnRect->right - lpColumnRect->left))
  1890.         return;
  1891.     ASSERT(lpszString);
  1892.     int iLength = _tcslen(lpszString);
  1893.     if (!iLength)
  1894.         return;
  1895.  
  1896.     UINT dwDTFormat = DT_NOCLIP | DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER;
  1897.     switch (alignment) {
  1898.     case AlignCenter:
  1899.         dwDTFormat |= DT_CENTER;
  1900.         break;
  1901.     case AlignRight:
  1902.         dwDTFormat |= DT_RIGHT;
  1903.         break;
  1904.     case AlignLeft:
  1905.     default:
  1906.         dwDTFormat |= DT_LEFT;
  1907.     }
  1908.  
  1909.     UINT dwMoreFormat = 0;
  1910.     switch (cropping) {
  1911.     case CropCenter:
  1912.         dwMoreFormat |= WFE_DT_CROPCENTER;
  1913.         break;
  1914.     case CropLeft:
  1915.         dwMoreFormat |= WFE_DT_CROPLEFT;
  1916.         break;
  1917.     case CropRight:
  1918.     default:
  1919.         dwMoreFormat |= WFE_DT_CROPRIGHT;
  1920.         break;
  1921.     }
  1922.  
  1923.     CRect textRect(*lpColumnRect);
  1924.     CRect bgRect;
  1925.     CString theString(lpszString);
  1926.  
  1927.     // Compute background rectangle
  1928.     DrawText(hdc, theString, theString.GetLength(), &bgRect, DT_CALCRECT | dwDTFormat);
  1929.     int w = bgRect.Width() + 2*COL_LEFT_MARGIN;
  1930.     if (w > textRect.Width())
  1931.         w = textRect.Width();
  1932.     bgRect.left = textRect.left;
  1933.     bgRect.top = textRect.top;
  1934.     bgRect.right = bgRect.left + w;
  1935.     bgRect.bottom = textRect.bottom;
  1936.  
  1937.     // Fill the background with the current brush (or frame if we don't have focus)
  1938.     if (ViewerHasFocus())
  1939.         ::FillRect(hdc, &bgRect, (HBRUSH) GetCurrentObject(hdc, OBJ_BRUSH));
  1940.     else if (theBrush)
  1941.         ::FrameRect( hdc, &bgRect, theBrush);
  1942.     
  1943.     // Adjust the text rectangle for the left and right margins
  1944.     textRect.left += COL_LEFT_MARGIN;
  1945.     textRect.right -= COL_LEFT_MARGIN;
  1946.  
  1947.     WFE_DrawTextEx( m_iCSID, hdc, (LPTSTR) lpszString, iLength, &textRect, dwDTFormat, dwMoreFormat );
  1948.  
  1949.     if (hasFocus)
  1950.     {
  1951.         DrawFocusRect ( hdc, &bgRect );
  1952.     }
  1953. }
  1954.  
  1955. int CRDFOutliner::DrawPipes ( int iLineNo, int iColNo, int offset, HDC hdc, void * pLineData )
  1956. {
  1957.     int iImageWidth = m_pIImage->GetImageWidth ( );
  1958.     int iMaxX = offset + m_pColumn[ iColNo ]->iCol;
  1959.     int idx;
  1960.  
  1961.     int iDepth;
  1962.     uint32 flags;
  1963.     OutlinerAncestorInfo * pAncestor;
  1964.     GetTreeInfo ( m_iTopLine + iLineNo, &flags, &iDepth, &pAncestor );
  1965.  
  1966.     RECT rect;
  1967.     rect.left = offset;
  1968.     rect.right = rect.left + iImageWidth;
  1969.     rect.top = iLineNo * m_itemHeight;
  1970.     rect.bottom = rect.top + m_itemHeight;
  1971.  
  1972.     if ( m_bHasPipes ) 
  1973.     {
  1974.         for ( int i = 0; i < iDepth; i++ ) 
  1975.         {
  1976.             if ( rect.right <= iMaxX ) 
  1977.             {
  1978.                 if ( pAncestor && pAncestor[ i ].has_next ) 
  1979.                 {
  1980.                     m_pIImage->DrawTransImage( IDX_VERTPIPE, rect.left, rect.top, hdc );
  1981.                 } 
  1982.                 else 
  1983.                 {
  1984.                     ::FillRect(hdc, &rect, (HBRUSH) GetCurrentObject(hdc, OBJ_BRUSH));
  1985.                 }
  1986.             }
  1987.             rect.left += iImageWidth;
  1988.             rect.right += iImageWidth;
  1989.         }
  1990.     
  1991.         if ( rect.right <= iMaxX ) {
  1992.             idx = 0;
  1993.             if ( pAncestor ) {
  1994.                 idx = GetPipeIndex ( pLineData, iDepth, &pAncestor[iDepth] );
  1995.             }
  1996.             if ( idx ) { 
  1997.                 m_pIImage->DrawTransImage( idx, rect.left, rect.top, hdc );
  1998.             } else {
  1999.                 ::FillRect(hdc, &rect, (HBRUSH) GetCurrentObject(hdc, OBJ_BRUSH));
  2000.             }
  2001.         }
  2002.         rect.left += iImageWidth;
  2003.         rect.right += iImageWidth;
  2004.     }
  2005.     if ( rect.right <= iMaxX ) {
  2006.         idx = TranslateIcon (pLineData);
  2007.         HT_Resource r = (HT_Resource)pLineData;
  2008.         if (idx == HTFE_USE_CUSTOM_IMAGE)
  2009.           DrawArbitraryURL(r, rect.left, rect.top, 16, 16, hdc, ::GetBkColor(hdc), this, FALSE);
  2010.         else if (idx == HTFE_LOCAL_FILE)
  2011.           DrawLocalFileIcon(r, rect.left, rect.top, hdc);
  2012.         else m_pIUserImage->DrawTransImage ( idx, rect.left, rect.top, hdc );
  2013.     }
  2014.     return rect.right;
  2015. }
  2016.  
  2017.  
  2018. void CRDFOutliner::ColumnsSwapped()
  2019. {
  2020.     SetImageColumn(m_pColumn[0]->iCommand);
  2021. }
  2022.  
  2023. CRect CRDFOutliner::GetColumnRect(int iLine, int column)
  2024. {
  2025.     CRect rectColumn;
  2026.     rectColumn.top = (iLine-m_iTopLine) * m_itemHeight;
  2027.     rectColumn.bottom = rectColumn.top + m_itemHeight;
  2028.     rectColumn.left = rectColumn.right = 0;
  2029.  
  2030.     int iColumn, offset;
  2031.     int iDepth;
  2032.     uint32 flags;
  2033.     OutlinerAncestorInfo * pAncestor;
  2034.     GetTreeInfo ( iLine, &flags, &iDepth, &pAncestor );
  2035.  
  2036.     for (iColumn = offset = 0; iColumn < m_iVisColumns; iColumn++)
  2037.     {
  2038.         if (m_pColumn[iColumn]->iCommand == m_idImageCol) 
  2039.         {
  2040.             // Handle the image column (where the indentation is)
  2041.             int iImageWidth = m_pIImage->GetImageWidth ( );
  2042.             rectColumn.left = (iImageWidth * (iDepth+1)) + OUTLINE_TEXT_OFFSET + m_pIUserImage->GetImageWidth();
  2043.         }
  2044.         else rectColumn.left = offset;
  2045.  
  2046.         rectColumn.right = offset + m_pColumn[ iColumn ]->iCol;
  2047.  
  2048.         if (m_pColumn[iColumn]->iCommand == (UINT)column)
  2049.             break;
  2050.  
  2051.         offset += m_pColumn[ iColumn ]->iCol;
  2052.     }
  2053.  
  2054.     return rectColumn;
  2055. }
  2056.  
  2057. char * CRDFOutliner::GetTextEditText(void)
  2058. {
  2059.     char str[1000];
  2060.  
  2061.     if(m_EditField)
  2062.     {
  2063.         int size = m_EditField->GetWindowText(str, 1000);
  2064.         if(size > 0)
  2065.         {
  2066.             char *newStr = new char[size + 1];
  2067.             strcpy(newStr, str);
  2068.             return newStr;
  2069.         }
  2070.     }
  2071.  
  2072.     return NULL;
  2073.  
  2074. }
  2075.  
  2076. // Edit window routines
  2077. void CRDFOutliner::EditTextChanged(char* text)
  2078. {
  2079.     if (text != NULL)
  2080.     {
  2081.         // Do stuff
  2082.  
  2083.         CRDFCommandMap& map = m_Parent->GetColumnCommandMap(); 
  2084.         CRDFColumn* theColumn = (CRDFColumn*)(map.GetCommand(m_nSelectedColumn));
  2085.         
  2086.         HT_SetNodeData(m_Node, theColumn->GetToken(), theColumn->GetDataType(), text);
  2087.  
  2088.         delete []text;
  2089.     }
  2090. }
  2091.  
  2092. void CRDFOutliner::AddTextEdit()
  2093. {
  2094.     BOOL bRtn = TRUE;
  2095.     if(!m_EditField)
  2096.     {
  2097.         m_EditField = new CRDFEditWnd(this);
  2098.         bRtn = m_EditField->Create(WS_BORDER | ES_AUTOHSCROLL, CRect(0,0,0,0), this, 0);
  2099.     }
  2100.  
  2101.     CRect rect;
  2102.     HDC hDC = ::GetDC(m_hWnd);
  2103.     HFONT hFont = WFE_GetUIFont(hDC);
  2104.     HFONT hOldFont = (HFONT)::SelectObject(hDC, hFont);
  2105.     TEXTMETRIC tm;
  2106.  
  2107.     GetTextMetrics(hDC, &tm);
  2108.     int height = tm.tmHeight;
  2109.     ::SelectObject(hDC, hOldFont);
  2110.     ::ReleaseDC(m_hWnd, hDC);
  2111.  
  2112.     rect = GetColumnRect(m_iSelection, m_nSelectedColumn);
  2113.     rect.bottom+=2; // Adjustment, since the default is a little too small
  2114.  
  2115.     if (rect.left == rect.right)
  2116.         bRtn = FALSE;
  2117.  
  2118.     if(!bRtn)
  2119.     {
  2120.         delete m_EditField;
  2121.         m_EditField = NULL;
  2122.     }
  2123.     else
  2124.     {
  2125.         m_EditField->MoveWindow(rect);
  2126.         m_EditField->ShowWindow(SW_SHOW);
  2127.         HDC hDC = ::GetDC(m_hWnd);
  2128.         HFONT hFont = WFE_GetUIFont(hDC);
  2129.         CFont *font = (CFont*) CFont::FromHandle(hFont);
  2130.         m_EditField->SetFont(font);
  2131.         ::ReleaseDC(m_hWnd, hDC);
  2132.         m_EditField->SetFocus();
  2133.  
  2134.         char* pText = (char*)GetColumnText(m_nSelectedColumn, HT_GetNthItem(m_View, m_iSelection));
  2135.  
  2136.         if (pText)
  2137.         {
  2138.             m_EditField->ReplaceSel(pText);
  2139.             m_EditField->SetSel(0, strlen(pText), TRUE);
  2140.         }
  2141.     }
  2142. }
  2143.  
  2144. void CRDFOutliner::RemoveTextEdit()
  2145. {
  2146.     if(m_EditField)
  2147.     {
  2148.         m_EditField->ShowWindow(SW_HIDE);
  2149.     }
  2150. }
  2151.  
  2152. void CRDFOutliner::MoveToNextColumn()
  2153. {
  2154.     int oldPos = GetColumnPos((UINT)m_nSelectedColumn);
  2155.     oldPos++;
  2156.     if (oldPos < (int)GetVisibleColumns())
  2157.     {
  2158.         m_nSelectedColumn = GetColumnAtPos(oldPos);
  2159.         RemoveTextEdit();
  2160.     }
  2161.     else 
  2162.     {
  2163.         m_nSelectedColumn = GetColumnAtPos(0);
  2164.         RemoveTextEdit();
  2165.         HT_Resource r = HT_GetNthItem(m_View, m_iSelection);
  2166.         if (r)
  2167.             HT_SetSelectedState(r, (PRBool)FALSE);
  2168.         m_iSelection++;
  2169.         m_iFocus = m_iSelection;
  2170.         HT_Resource r2 = HT_GetNthItem(m_View, m_iSelection);
  2171.         if (!r2)
  2172.         {
  2173.             m_iFocus = -1;
  2174.             m_iSelection = -1;
  2175.             m_Node = NULL;
  2176.             return;
  2177.         }
  2178.  
  2179.         CRDFCommandMap& map = m_Parent->GetColumnCommandMap(); 
  2180.         CRDFColumn* theColumn = (CRDFColumn*)(map.GetCommand(m_nSelectedColumn));
  2181.         
  2182.         BOOL isEditable = HT_IsNodeDataEditable(r2, theColumn->GetToken(), 
  2183.                                                     theColumn->GetDataType());
  2184.         if (!isEditable)
  2185.         {
  2186.             m_iFocus = -1;
  2187.             m_iSelection = -1;
  2188.             m_Node = NULL;
  2189.             return;
  2190.         }
  2191.  
  2192.         HT_SetSelectedState(r2, (PRBool)TRUE);
  2193.  
  2194.         m_Node = r2;
  2195.     }
  2196.     
  2197.     AddTextEdit();
  2198. }
  2199.  
  2200.  
  2201. void CRDFOutliner::OnTimer(UINT nID)
  2202. {
  2203.     COutliner::OnTimer(nID);
  2204.     if (nID == IDT_EDITFOCUS) 
  2205.     {
  2206.         if (m_hEditTimer != 0)
  2207.         {
  2208.             KillTimer(m_hEditTimer);
  2209.             m_hEditTimer = 0;
  2210.         }    
  2211.         AddTextEdit();        
  2212.     }
  2213.     else if (nID == IDT_SPRINGLOAD)
  2214.     {
  2215.         if (m_hSpringloadTimer != 0) 
  2216.         {
  2217.             KillTimer(m_hSpringloadTimer);
  2218.             m_hSpringloadTimer = 0;
  2219.         
  2220.             if (m_iDragSelection == m_iSpringloadSelection)
  2221.             {
  2222.                 // Open the folder
  2223.                 HT_Resource r = HT_GetNthItem(m_View, m_iDragSelection);
  2224.                 if (r != NULL)
  2225.                 {
  2226.                     // Pop it open
  2227.                     HT_SetOpenState(r, (PRBool)TRUE);
  2228.  
  2229.                     // Add this folder to our list of springloaded folders
  2230.                     m_SpringloadStack.AddHead((void*)r);
  2231.                 }
  2232.             }
  2233.         }
  2234.     }
  2235.     else if (nID == IDT_DRAGRECT)
  2236.     {
  2237.         if (m_hDragRectTimer != 0)
  2238.         {
  2239.             KillTimer(m_hDragRectTimer);
  2240.             m_hDragRectTimer = 0;
  2241.  
  2242.             CRect rect;
  2243.             GetClientRect(&rect);
  2244.  
  2245.             if (m_MovePoint.y < m_itemHeight)
  2246.             {
  2247.                 DragRectScroll(TRUE);
  2248.                 m_hDragRectTimer = SetTimer(IDT_DRAGRECT, GetDragHeartbeat(), NULL);
  2249.             }
  2250.  
  2251.             else if (m_MovePoint.y > rect.bottom - m_itemHeight)
  2252.             {
  2253.                 DragRectScroll(FALSE);
  2254.                 m_hDragRectTimer = SetTimer(IDT_DRAGRECT, GetDragHeartbeat(), NULL);
  2255.             }
  2256.         }
  2257.     }
  2258. }
  2259.  
  2260. // DRAG AND DROP ROUTINES
  2261. int CRDFOutliner::GetDragHeartbeat()
  2262. {
  2263.     return RDF_DRAG_HEARTBEAT;
  2264. }
  2265.  
  2266. COleDataSource * CRDFOutliner::GetDataSource()
  2267. {
  2268.     m_bNeedToClear = FALSE; // Hack. Just leave it here, and don't worry about it.
  2269.  
  2270.     COleDataSource * pDataSource = new COleDataSource;  
  2271.  
  2272.     HANDLE hString = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE,1);
  2273.     pDataSource->CacheGlobalData(m_cfHTNode, hString);
  2274.  
  2275.     // The view is sufficient
  2276.     RDFGLOBAL_BeginDrag(pDataSource, m_View);
  2277.     
  2278.     return pDataSource;
  2279. }
  2280.  
  2281. void RDFGLOBAL_BeginDrag(COleDataSource* pDataSource, HT_View pView)
  2282. {
  2283.     CLIPFORMAT cfBookmark = (CLIPFORMAT) RegisterClipboardFormat( NETSCAPE_HTNODE_FORMAT );
  2284.     HGLOBAL hBookmark = GlobalAlloc( GMEM_DDESHARE | GMEM_ZEROINIT, sizeof(HT_View) );
  2285.     if( hBookmark ) 
  2286.     {
  2287.         HT_View* pBookmark = (HT_View*) GlobalLock( hBookmark );
  2288.         *pBookmark = pView;
  2289.         GlobalUnlock( hBookmark);
  2290.         pDataSource->CacheGlobalData( cfBookmark, hBookmark );
  2291.     }
  2292.  
  2293.     // Get the selected items and set up internet shortcut
  2294.     // drag if the item is not a container or separator.
  2295.     int selCount = 0;
  2296.     HT_Resource r = HT_GetNextSelection(pView, NULL);
  2297.     while (r != NULL)
  2298.     {
  2299.         if (!HT_IsContainer(r) && !HT_IsSeparator(r))
  2300.             selCount++;
  2301.         r = HT_GetNextSelection(pView, r);
  2302.     }
  2303.  
  2304.     CString* titleArray = new CString[selCount];
  2305.     CString* urlArray = new CString[selCount];
  2306.     int i = -1;
  2307.     r = HT_GetNextSelection(pView, NULL);
  2308.     while (r != NULL)
  2309.     {
  2310.         if (!HT_IsContainer(r) && !HT_IsSeparator(r))
  2311.         {
  2312.             i++; // Found one
  2313.             titleArray[i] = HT_GetNodeName(r);
  2314.             urlArray[i] = HT_GetNodeURL(r);
  2315.         }
  2316.         r = HT_GetNextSelection(pView, r);
  2317.     }
  2318.     DragMultipleShortcuts(pDataSource, titleArray, urlArray, selCount);
  2319.     delete []titleArray;
  2320.     delete []urlArray;
  2321. }
  2322.  
  2323. void RDFGLOBAL_DragTitleAndURL( COleDataSource *pDataSource, LPCSTR title, LPCSTR url )
  2324. {
  2325.     CLIPFORMAT cfBookmark = (CLIPFORMAT) RegisterClipboardFormat( NETSCAPE_BOOKMARK_FORMAT );
  2326.     HGLOBAL hBookmark = GlobalAlloc( GMEM_DDESHARE | GMEM_ZEROINIT, sizeof(BOOKMARKITEM) );
  2327.     if( hBookmark ) {
  2328.         LPBOOKMARKITEM pBookmark = (LPBOOKMARKITEM) GlobalLock( hBookmark );
  2329.         PR_snprintf( pBookmark->szAnchor, sizeof(pBookmark->szAnchor),"%s", url );
  2330.         PR_snprintf( pBookmark->szText, sizeof(pBookmark->szText),"%s", title );
  2331.         GlobalUnlock( hBookmark);
  2332.  
  2333.         pDataSource->CacheGlobalData( cfBookmark, hBookmark );
  2334.     }
  2335.  
  2336.     HGLOBAL hString = GlobalAlloc( GMEM_MOVEABLE|GMEM_DDESHARE, strlen( url ) + 1 );
  2337.     if ( hString ) {
  2338.         LPSTR lpszString = (LPSTR) GlobalLock( hString );
  2339.         strcpy( lpszString, url );
  2340.         GlobalUnlock( hString );
  2341.  
  2342.         pDataSource->CacheGlobalData( CF_TEXT, hString );
  2343.     }
  2344.  
  2345.     // Do an internet shortcut drag
  2346.     DragInternetShortcut(pDataSource, title, url);
  2347. }
  2348.  
  2349.  
  2350. COutlinerDropTarget* CRDFOutliner::CreateDropTarget()
  2351. {
  2352.     return new CRDFDropTarget(this);
  2353. }
  2354.  
  2355. BOOL CRDFOutliner::HighlightIfDragging(void)
  2356. {
  2357.     if(m_iDragSelection != -1)
  2358.     {
  2359.         HT_Resource r = HT_GetNthItem(m_View, m_iDragSelection);
  2360.         if (r != NULL && HT_IsContainer(r) && (m_iDragSelectionLineThird == 2 || (GetSortColumn() != -1)))
  2361.             return TRUE;
  2362.     }
  2363.     return FALSE;
  2364. }
  2365.  
  2366. void CRDFOutliner::PaintDragLine(HDC hdc, CRect &rectColumn)
  2367. {
  2368.     HPEN pen = ::CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNSHADOW));
  2369.     HPEN pOldPen = (HPEN)::SelectObject(hdc, pen);
  2370.  
  2371.     if(m_iDragSelectionLineThird == 1) {
  2372. #ifdef XP_WIN32
  2373.         MoveToEx(hdc, rectColumn.left, rectColumn.top, NULL);
  2374. #else
  2375.         MoveTo(hdc, rectColumn.left, rectColumn.top);
  2376. #endif
  2377.         LineTo(hdc, rectColumn.right, rectColumn.top);
  2378.     }
  2379.     else if(m_iDragSelectionLineThird == 3){
  2380. #ifdef XP_WIN32
  2381.         MoveToEx(hdc, rectColumn.left, rectColumn.bottom -1, NULL);
  2382. #else
  2383.         MoveTo(hdc, rectColumn.left, rectColumn.bottom - 1);
  2384. #endif
  2385.         LineTo(hdc, rectColumn.right, rectColumn.bottom - 1);
  2386.     }
  2387.  
  2388.     ::SelectObject(hdc, pOldPen);
  2389.     ::DeleteObject(pen);
  2390. }
  2391.  
  2392. void CRDFOutliner::AcceptDrop( int iLineNo, COleDataObject *pDataObject, DROPEFFECT dropEffect )
  2393. {
  2394.     HT_Resource theNode = NULL;
  2395.     if (iLineNo >= 0)
  2396.         theNode = HT_GetNthItem(m_View, iLineNo);
  2397.     if (theNode == NULL)
  2398.         theNode = HT_TopNode(m_View);
  2399.  
  2400.     RDFGLOBAL_PerformDrop(pDataObject, theNode, m_iDragSelectionLineThird);
  2401.  
  2402.     m_SpringloadStack.RemoveAll();
  2403. }
  2404.  
  2405. void RDFGLOBAL_PerformDrop(COleDataObject* pDataObject, HT_Resource theNode, int dragFraction)
  2406. {
  2407.     if(!pDataObject)
  2408.         return;
  2409.  
  2410.     CLIPFORMAT cfHTNode = (CLIPFORMAT)RegisterClipboardFormat(NETSCAPE_HTNODE_FORMAT);
  2411.     CLIPFORMAT cfBookmark = (CLIPFORMAT)RegisterClipboardFormat(NETSCAPE_BOOKMARK_FORMAT);
  2412.     
  2413.     if(!pDataObject->IsDataAvailable(CF_TEXT) &&
  2414.        !pDataObject->IsDataAvailable(cfHTNode) &&
  2415.        !pDataObject->IsDataAvailable(cfBookmark) &&
  2416.        !pDataObject->IsDataAvailable(CF_HDROP))
  2417.        return;
  2418.  
  2419.     if(pDataObject->IsDataAvailable(cfHTNode)) 
  2420.     {
  2421.         HT_View pView = NULL;
  2422.  
  2423.         HGLOBAL hBookmark = pDataObject->GetGlobalData(cfHTNode);
  2424.         HT_View* pBookmark = (HT_View*)GlobalLock(hBookmark);
  2425.         ASSERT(pBookmark);
  2426.         pView = *pBookmark;
  2427.         GlobalUnlock(hBookmark);
  2428.  
  2429.         DropPosition dropPosition = RDFGLOBAL_TranslateDropPosition(theNode, dragFraction);
  2430.  
  2431.         HT_Resource node = NULL;
  2432.         while (node = (HT_GetNextSelection(pView, node)))
  2433.         {
  2434.             if (dropPosition == DROP_BEFORE)
  2435.                 HT_DropHTRAtPos(theNode, node, (PRBool)TRUE);
  2436.             else if (dropPosition == DROP_AFTER)
  2437.                 HT_DropHTRAtPos(theNode, node, (PRBool)FALSE);
  2438.             else if (dropPosition == DROP_ON)
  2439.                 HT_DropHTROn(theNode, node);
  2440.             else HT_DropHTROn(HT_GetParent(theNode), node);
  2441.         }
  2442.     }
  2443.     else if(pDataObject->IsDataAvailable(cfBookmark)) 
  2444.     {
  2445.         HGLOBAL hBookmark = pDataObject->GetGlobalData(cfBookmark);
  2446.         LPBOOKMARKITEM pBookmark = (LPBOOKMARKITEM)GlobalLock(hBookmark);
  2447.         ASSERT(pBookmark);
  2448.         CString title(pBookmark->szText);
  2449.         CString url(pBookmark->szAnchor);
  2450.  
  2451.         GlobalUnlock(hBookmark);
  2452.  
  2453.         DropPosition dropPosition = RDFGLOBAL_TranslateDropPosition(theNode, dragFraction);
  2454.         if (dropPosition == DROP_BEFORE)
  2455.             HT_DropURLAndTitleAtPos(theNode, (char*)(const char*)url, (char*)(const char*)title, (PRBool)TRUE);
  2456.         else if (dropPosition == DROP_AFTER)
  2457.             HT_DropURLAndTitleAtPos(theNode, (char*)(const char*)url, (char*)(const char*)title, (PRBool)FALSE);
  2458.         else if (dropPosition == DROP_ON)
  2459.             HT_DropURLAndTitleOn(theNode, (char*)(const char*)url, (char*)(const char*)title);
  2460.         else HT_DropURLAndTitleOn(HT_GetParent(theNode), (char*)(const char*)url, (char*)(const char*)title);
  2461.     }
  2462.     else if (pDataObject->IsDataAvailable(CF_HDROP))
  2463.     {
  2464.         HGLOBAL hGlobal = pDataObject->GetGlobalData(CF_HDROP);
  2465.         HDROP hDropInfo = (HDROP)hGlobal;
  2466.         
  2467.         // Get the number of files dropped
  2468.         int i_num = ::DragQueryFile(hDropInfo, (UINT)-1, NULL, 0);
  2469.  
  2470.         char ca_drop[_MAX_PATH];
  2471.         CString csUnescapedUrl, csEscapedUrl;
  2472.  
  2473.         int i_loop;
  2474.         for(i_loop = 0; i_loop < i_num; i_loop++)  
  2475.         {
  2476.             ::DragQueryFile(hDropInfo, i_loop, ca_drop, _MAX_PATH);
  2477.  
  2478.             //  Convert to an acceptable URL.
  2479.             WFE_ConvertFile2Url(csUnescapedUrl, ca_drop);
  2480.             csEscapedUrl = WFE_EscapeURL(csUnescapedUrl);
  2481.  
  2482.             // Tell HT about the drop
  2483.             DropPosition dropPosition = RDFGLOBAL_TranslateDropPosition(theNode, dragFraction);
  2484.             if (dropPosition == DROP_BEFORE)
  2485.                 HT_DropURLAtPos(theNode, (char*)(const char*)csEscapedUrl, (PRBool)TRUE);
  2486.             else if (dropPosition == DROP_AFTER)
  2487.                 HT_DropURLAtPos(theNode, (char*)(const char*)csEscapedUrl, (PRBool)FALSE);
  2488.             else if (dropPosition == DROP_ON)
  2489.                 HT_DropURLOn(theNode, (char*)(const char*)csEscapedUrl);
  2490.             else HT_DropURLOn(HT_GetParent(theNode), (char*)(const char*)csEscapedUrl);
  2491.         }
  2492.         GlobalUnlock(hGlobal);
  2493.     }
  2494.     else if (pDataObject->IsDataAvailable(CF_TEXT))
  2495.     {
  2496.         HGLOBAL hString = pDataObject->GetGlobalData(CF_TEXT);
  2497.         char * pAddress = (char*)GlobalLock(hString);
  2498.         CString url(pAddress);
  2499.         GlobalUnlock(hString);
  2500.  
  2501.         DropPosition dropPosition = RDFGLOBAL_TranslateDropPosition(theNode, dragFraction);
  2502.         if (dropPosition == DROP_BEFORE)
  2503.             HT_DropURLAtPos(theNode, (char*)(const char*)url, (PRBool)TRUE);
  2504.         else if (dropPosition == DROP_AFTER)
  2505.             HT_DropURLAtPos(theNode, (char*)(const char*)url, (PRBool)FALSE);
  2506.         else if (dropPosition == DROP_ON)
  2507.             HT_DropURLOn(theNode, (char*)(const char*)url);
  2508.         else HT_DropURLOn(HT_GetParent(theNode), (char*)(const char*)url);
  2509.     }
  2510.     
  2511. }
  2512.  
  2513. void CRDFOutliner::InitializeClipFormats(void)
  2514. {
  2515.     m_cfHTNode = (CLIPFORMAT)RegisterClipboardFormat(NETSCAPE_HTNODE_FORMAT);
  2516.     m_cfBookmark = (CLIPFORMAT)RegisterClipboardFormat(NETSCAPE_BOOKMARK_FORMAT);
  2517.     
  2518.     m_clipFormatArray[0] = m_cfHTNode;
  2519.     m_clipFormatArray[1] = m_cfBookmark;
  2520.     m_clipFormatArray[2] = CF_HDROP;
  2521.     m_clipFormatArray[3] = CF_TEXT;
  2522.     m_clipFormatArray[4] = 0;
  2523. }
  2524.  
  2525. CLIPFORMAT * CRDFOutliner::GetClipFormatList(void)
  2526. {
  2527.     return m_clipFormatArray;
  2528. }
  2529.  
  2530. DROPEFFECT CRDFOutliner::DropSelect(int iLineNo, COleDataObject *object)
  2531. {
  2532.     HT_Resource r = NULL;
  2533.     if (iLineNo >= 0)
  2534.         r = HT_GetNthItem(m_View, iLineNo);
  2535.     if (r == NULL)
  2536.         r = HT_TopNode(m_View);
  2537.  
  2538.     DROPEFFECT answer = RDFGLOBAL_TranslateDropAction(r, object, 
  2539.         HT_IsContainer(r) ? m_iDragSelectionLineThird : m_iDragSelectionLineHalf);
  2540.     
  2541.     m_iCurrentDropAction = answer;
  2542.  
  2543.     if (iLineNo == m_iDragSelection && !m_bDragSectionChanged)
  2544.         return answer;
  2545.  
  2546.     if (m_iDragSelection != -1)
  2547.         InvalidateLine (m_iDragSelection);
  2548.  
  2549.     m_iDragSelection = iLineNo;
  2550.     InvalidateLine (m_iDragSelection);
  2551.     
  2552.     // Start the hover timer for folder springloading
  2553.     
  2554.     if (m_iDragSelection != -1)
  2555.     {
  2556.         if (r != NULL && HT_IsContainer(r) && !HT_IsContainerOpen(r) && m_iCurrentDropAction != DROPEFFECT_NONE)
  2557.         {
  2558.              m_iSpringloadSelection = m_iDragSelection;
  2559.             m_hSpringloadTimer = SetTimer(IDT_SPRINGLOAD, SPRINGLOAD_DELAY, NULL);
  2560.         }
  2561.     }
  2562.  
  2563.     // Check for springload closing time
  2564.     if (!m_SpringloadStack.IsEmpty())
  2565.     {
  2566.         // There are some springloaded folders that might need to be closed.
  2567.         POSITION p = m_SpringloadStack.GetHeadPosition();
  2568.         HT_Resource r = (HT_Resource)m_SpringloadStack.GetNext(p);
  2569.  
  2570.         int count = (int)HT_GetCountVisibleChildren(r);
  2571.         int index = (int)HT_GetNodeIndex(m_View, r);
  2572.         
  2573.         if (m_iDragSelection < index ||
  2574.             m_iDragSelection == -1 ||
  2575.             m_iDragSelection > index + count)
  2576.         {
  2577.             m_SpringloadStack.RemoveHead();
  2578.             HT_SetOpenState(r, (PRBool)FALSE);
  2579.         
  2580.             if (m_iDragSelection > index + count)
  2581.                 m_iDragSelection -= count;
  2582.         }
  2583.     }
  2584.     return answer;
  2585. }
  2586.  
  2587. DropPosition RDFGLOBAL_TranslateDropPosition(HT_Resource dropTarget, int position)
  2588. {
  2589.     HT_Resource targetParent = HT_GetParent(dropTarget);
  2590.  
  2591.     BOOL sortImposed = !HT_ContainerSupportsNaturalOrderSort(targetParent); // Is a sort imposed on the parent?
  2592.  
  2593.     DropPosition res;
  2594.     if (targetParent == NULL) // Top Node of the view.  Can't drop before or after.
  2595.         res = DROP_ON;
  2596.     else if (!sortImposed) // Can only drop/before or after if sort is not imposed on the view.
  2597.     {
  2598.         if (position == 1)
  2599.         {
  2600.             // Drop before
  2601.             res = DROP_BEFORE; // In upper half of selection (for non-containers) or bottom third 
  2602.                                // of selection (for containers).  Drop before.
  2603.         }
  2604.         else if (position == 3 || (position == 2 && !HT_IsContainer(dropTarget)))
  2605.         {
  2606.             // Drop after if we're in the bottom half (for non-containers) or bottom third (for containers)
  2607.             res = DROP_AFTER;  // In lower third of selection.  Drop after.
  2608.         }
  2609.         else res = DROP_ON;  // We're a container and right in the middle of selection.  Drop on.
  2610.     }
  2611.     else if (HT_IsContainer(dropTarget))
  2612.     {
  2613.         res = DROP_ON; // If a sort is imposed and we're over a container, drop into that.
  2614.     }
  2615.     else res = DROP_ON_PARENT;  // Otherwise, we'll drop into the parent container and let the sort
  2616.                                 // put it where it's supposed to go.
  2617.  
  2618.     return res;
  2619. }
  2620.  
  2621. DROPEFFECT RDFGLOBAL_TranslateDropAction(HT_Resource dropTarget, COleDataObject* pDataObject, 
  2622.                                          int position)
  2623. {
  2624.     HT_DropAction res;
  2625.     CLIPFORMAT cfHTNode = (CLIPFORMAT)RegisterClipboardFormat(NETSCAPE_HTNODE_FORMAT);
  2626.     CLIPFORMAT cfBookmark = (CLIPFORMAT)RegisterClipboardFormat(NETSCAPE_BOOKMARK_FORMAT);
  2627.  
  2628.     if (dropTarget == NULL)
  2629.         return DROPEFFECT_NONE;
  2630.  
  2631.     DropPosition dropPosition = RDFGLOBAL_TranslateDropPosition(dropTarget, position);
  2632.         
  2633.     if(pDataObject->IsDataAvailable(cfHTNode)) 
  2634.     {
  2635.         HT_View pView = NULL;
  2636.  
  2637.         HGLOBAL hBookmark = pDataObject->GetGlobalData(cfHTNode);
  2638.         HT_View* pBookmark = (HT_View*)GlobalLock(hBookmark);
  2639.         ASSERT(pBookmark);
  2640.         pView = *pBookmark;
  2641.         GlobalUnlock(hBookmark);
  2642.  
  2643.         HT_Resource node = HT_GetNextSelection(pView, NULL);         
  2644.         while (node != NULL)
  2645.         {
  2646.             HT_DropAction res2;
  2647.             if (dropPosition == DROP_BEFORE)
  2648.                 res2 = HT_CanDropHTRAtPos(dropTarget, node, (PRBool)TRUE); 
  2649.             else if (dropPosition == DROP_AFTER)
  2650.                 res2 = HT_CanDropHTRAtPos(dropTarget, node, (PRBool)FALSE);
  2651.             else if (dropPosition == DROP_ON)
  2652.                 res2 = HT_CanDropHTROn(dropTarget, node);
  2653.             else res2 = HT_CanDropHTROn(HT_GetParent(dropTarget), node);
  2654.  
  2655.             if (res2 == DROP_NOT_ALLOWED)
  2656.             {
  2657.                 res = DROP_NOT_ALLOWED;
  2658.                 break;
  2659.             }
  2660.             
  2661.             res = res2;
  2662.  
  2663.             node = HT_GetNextSelection(pView, node);
  2664.         }
  2665.     }
  2666.     else if (pDataObject->IsDataAvailable(cfBookmark))
  2667.     {
  2668.         HGLOBAL hBookmark = pDataObject->GetGlobalData(cfBookmark);
  2669.         LPBOOKMARKITEM pBookmark = (LPBOOKMARKITEM)GlobalLock(hBookmark);
  2670.         ASSERT(pBookmark);
  2671.         CString title(pBookmark->szText);
  2672.         CString url(pBookmark->szAnchor);
  2673.  
  2674.         GlobalUnlock(hBookmark);
  2675.         
  2676.         if (dropPosition == DROP_BEFORE)
  2677.           res = HT_CanDropURLAtPos(dropTarget, (char*)(const char*)url, (PRBool)TRUE); 
  2678.         else if (dropPosition == DROP_AFTER)
  2679.           res = HT_CanDropURLAtPos(dropTarget, (char*)(const char*)url, (PRBool)FALSE);
  2680.         else if (dropPosition == DROP_ON)
  2681.           res = HT_CanDropURLOn(dropTarget, (char*)(const char*)url);
  2682.         else res = HT_CanDropURLOn(HT_GetParent(dropTarget), (char*)(const char*)url);
  2683.     }
  2684.     else if (pDataObject->IsDataAvailable(CF_HDROP))
  2685.     {
  2686.         HGLOBAL hGlobal = pDataObject->GetGlobalData(CF_HDROP);
  2687.         HDROP hDropInfo = (HDROP)hGlobal;
  2688.         
  2689.         // Get the number of files dropped
  2690.         int i_num = ::DragQueryFile(hDropInfo, (UINT)-1, NULL, 0);
  2691.  
  2692.         char ca_drop[_MAX_PATH];
  2693.         CString csUnescapedUrl, csEscapedUrl;
  2694.  
  2695.         int i_loop;
  2696.         HT_DropAction res2;
  2697.         for(i_loop = 0; i_loop < i_num; i_loop++)  
  2698.         {
  2699.             ::DragQueryFile(hDropInfo, i_loop, ca_drop, _MAX_PATH);
  2700.  
  2701.             //  Convert to an acceptable URL.
  2702.             WFE_ConvertFile2Url(csUnescapedUrl, ca_drop);
  2703.             csEscapedUrl = WFE_EscapeURL(csUnescapedUrl);
  2704.  
  2705.             // Tell HT about the drop
  2706.             if (dropPosition == DROP_BEFORE)
  2707.                 res2 = HT_CanDropURLAtPos(dropTarget, (char*)(const char*)csEscapedUrl, (PRBool)TRUE);
  2708.             else if (dropPosition == DROP_AFTER)
  2709.                 res2 = HT_CanDropURLAtPos(dropTarget, (char*)(const char*)csEscapedUrl, (PRBool)FALSE);
  2710.             else if (dropPosition == DROP_ON)
  2711.                 res2 = HT_CanDropURLOn(dropTarget, (char*)(const char*)csEscapedUrl);
  2712.             else res2 = HT_CanDropURLOn(HT_GetParent(dropTarget), (char*)(const char*)csEscapedUrl);
  2713.  
  2714.             if (res2 == DROP_NOT_ALLOWED)
  2715.             {
  2716.                 res = DROP_NOT_ALLOWED;
  2717.                 break;
  2718.             }
  2719.             
  2720.             res = res2;
  2721.         }
  2722.         GlobalUnlock(hGlobal);
  2723.     }
  2724.     else if (pDataObject->IsDataAvailable(CF_TEXT))
  2725.     {
  2726.         HGLOBAL hString = pDataObject->GetGlobalData(CF_TEXT);
  2727.         char * pAddress = (char*)GlobalLock(hString);
  2728.         CString url(pAddress);
  2729.         GlobalUnlock(hString);
  2730.  
  2731.         if (dropPosition == DROP_BEFORE)
  2732.           res = HT_CanDropURLAtPos(dropTarget, (char*)(const char*)url, (PRBool)TRUE); 
  2733.         else if (dropPosition == DROP_AFTER)
  2734.           res = HT_CanDropURLAtPos(dropTarget, (char*)(const char*)url, (PRBool)FALSE);
  2735.         else if (dropPosition == DROP_ON)
  2736.           res = HT_CanDropURLOn(dropTarget, (char*)(const char*)url);
  2737.         else res = HT_CanDropURLOn(HT_GetParent(dropTarget), (char*)(const char*)url);
  2738.     }
  2739.  
  2740.     switch (res)
  2741.     {
  2742.         case DROP_NOT_ALLOWED:
  2743.             return DROPEFFECT_NONE;
  2744.         case COPY_MOVE_CONTENT:
  2745.         case COPY_MOVE_LINK:
  2746.             return DROPEFFECT_MOVE;
  2747.         default:
  2748.             return DROPEFFECT_COPY;
  2749.     }
  2750. }
  2751.  
  2752. // RDFDropTarget Overridden Funcs
  2753.  
  2754. BOOL CRDFDropTarget::OnDrop(
  2755.     CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point)
  2756. {
  2757.     m_dwOldTicks = 0;
  2758.  
  2759.     CRDFOutliner* pOutliner = (CRDFOutliner*)m_pOutliner;
  2760.  
  2761.     if(!pDataObject || !pOutliner)
  2762.         return(FALSE);
  2763.  
  2764.     if (!pOutliner->RecognizedFormat(pDataObject))
  2765.         return FALSE;
  2766.  
  2767.     pOutliner->m_ptHit = point;
  2768.  
  2769.     pOutliner->AcceptDrop( point.y < 0 ? -1 : pOutliner->GetDropLine(), pDataObject, dropEffect);
  2770.     pOutliner->EndDropSelect();
  2771.  
  2772.     return(TRUE);
  2773. }
  2774.  
  2775. DROPEFFECT CRDFDropTarget::OnDragEnter(
  2776.     CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
  2777. {
  2778.     DROPEFFECT res = OnDragOver(pWnd, pDataObject, dwKeyState, point);
  2779.  
  2780.     CRDFOutliner* pOutliner = (CRDFOutliner*)m_pOutliner;
  2781.     pOutliner->m_bDataSourceInWindow = TRUE;
  2782.  
  2783.     if ( res != DROPEFFECT_NONE && point.y >= 0) {
  2784.         m_pOutliner->Invalidate();
  2785.         m_pOutliner->UpdateWindow();
  2786.     }
  2787.  
  2788.     return res;
  2789. }
  2790.  
  2791. DROPEFFECT CRDFDropTarget::OnDragOver(
  2792.     CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
  2793. {
  2794.     DROPEFFECT effect = DROPEFFECT_NONE;
  2795.     CRDFOutliner* pOutliner = (CRDFOutliner*)m_pOutliner;
  2796.  
  2797.     if (pOutliner->RecognizedFormat(pDataObject)) {
  2798.         RECT rect;
  2799.         pWnd->GetClientRect(&rect);
  2800.  
  2801.         if ( point.y < pOutliner->m_itemHeight && point.y >= 0) {
  2802.             DragScroll(TRUE);
  2803.             effect |= DROPEFFECT_SCROLL;
  2804.         } else if ( point.y > ( rect.bottom - pOutliner->m_itemHeight ) ) {
  2805.             DragScroll(FALSE);
  2806.             effect |= DROPEFFECT_SCROLL;
  2807.         } else {
  2808.             m_dwOldTicks = 0;
  2809.         }
  2810.  
  2811.         pOutliner->m_ptHit = point;
  2812.  
  2813.         effect |= pOutliner->DropSelect(point.y < 0 ? -1 : pOutliner->LineFromPoint(point), pDataObject);
  2814.  
  2815.         // Default is to move
  2816.         if ( ( effect & DROPEFFECT_MOVE) && (dwKeyState & MK_CONTROL) )
  2817.             effect = (effect & ~DROPEFFECT_MOVE) | DROPEFFECT_COPY;
  2818.     }
  2819.     return effect;
  2820. }
  2821.  
  2822. void CRDFDropTarget::OnDragLeave(CWnd* pWnd)
  2823. {
  2824.     CRDFOutliner* pOutliner = (CRDFOutliner*)m_pOutliner;
  2825.     for (POSITION p = pOutliner->m_SpringloadStack.GetHeadPosition(); p != NULL; )
  2826.     {
  2827.         HT_Resource r = (HT_Resource)(pOutliner->m_SpringloadStack.GetNext(p));
  2828.         HT_SetOpenState(r, (PRBool)FALSE);
  2829.     }
  2830.              
  2831.     pOutliner->m_SpringloadStack.RemoveAll();
  2832.  
  2833.     pOutliner->m_bDataSourceInWindow = FALSE;
  2834.  
  2835.     pOutliner->m_iDragSelection = -1;
  2836.  
  2837.     pOutliner->Invalidate();
  2838.     pOutliner->UpdateWindow();
  2839. }
  2840.  
  2841. // ========================================================================
  2842.  
  2843. BEGIN_MESSAGE_MAP(CRDFOutlinerParent,COutlinerParent)
  2844.     ON_WM_DESTROY()
  2845. END_MESSAGE_MAP()
  2846.  
  2847. CRDFOutlinerParent::CRDFOutlinerParent(HT_Pane thePane, HT_View theView)
  2848. {
  2849.     CRDFOutliner* theOutliner = new CRDFOutliner(thePane, theView, this);
  2850.     m_pOutliner = theOutliner;
  2851. }
  2852.  
  2853. BOOL CRDFOutlinerParent::PreCreateWindow(CREATESTRUCT& cs)
  2854. {
  2855.     BOOL bRet = CWnd::PreCreateWindow(cs);
  2856.  
  2857. //#ifdef XP_WIN32
  2858. //    cs.dwExStyle |= WS_EX_CLIENTEDGE;
  2859. //#endif
  2860.     return bRet;
  2861. }
  2862.  
  2863. void CRDFOutlinerParent::OnDestroy()
  2864. {
  2865.     // Save prefs might happen here...
  2866.     COutlinerParent::OnDestroy();
  2867. }
  2868.  
  2869. COutliner* CRDFOutlinerParent::GetOutliner ( )
  2870. {
  2871.     return m_pOutliner;
  2872. }
  2873.  
  2874. void CRDFOutlinerParent::CreateColumns ( void )
  2875. {
  2876.     // Retrieve the columns from RDF
  2877.     CRDFOutliner* theOutliner = (CRDFOutliner*)m_pOutliner;
  2878.     HT_View theView = theOutliner->GetHTView();
  2879.     
  2880.     HT_Cursor columnCursor = HT_NewColumnCursor(theView);
  2881.     char* columnName;
  2882.     uint32 columnWidth;
  2883.     void* token;
  2884.     uint32 tokenType;
  2885.     UINT index = 0;
  2886.     while (HT_GetNextColumn(columnCursor, &columnName, &columnWidth, &token, &tokenType))
  2887.     {
  2888.         // We have retrieved a new column.  Contruct a front end column object
  2889.         CRDFColumn* newColumn = new CRDFColumn(columnName, columnWidth, token, tokenType);
  2890.         index = (UINT)columnMap.AddCommand(newColumn);
  2891.         m_pOutliner->AddColumn(columnName, index, 5000, 10000, ColumnVariable, 3000);
  2892.     }
  2893.     HT_DeleteColumnCursor(columnCursor);
  2894.     m_pOutliner->SetVisibleColumns(1); // For now... TODO: Get visible/invisible info!
  2895.     m_pOutliner->SetImageColumn(0);
  2896. }
  2897.  
  2898. BOOL CRDFOutlinerParent::RenderData( int iColumn, CRect & rect, CDC &dc, LPCTSTR text )
  2899. {
  2900.     CRDFOutliner *pOutliner = (CRDFOutliner *)m_pOutliner;
  2901.     
  2902.     if( !pOutliner )
  2903.     {
  2904.        return FALSE;
  2905.     }
  2906.      
  2907.     if( pOutliner->GetSortType() == HT_NO_SORT)
  2908.     {
  2909.        return FALSE;
  2910.     }
  2911.     
  2912.     MSG_COMMAND_CHECK_STATE sortType = (iColumn == pOutliner->GetSortColumn()) ? MSG_Checked : MSG_Unchecked;
  2913.     
  2914.     if( sortType != MSG_Checked )
  2915.     {
  2916.        return FALSE;
  2917.     }
  2918.  
  2919.     int idxImage = (pOutliner->GetSortType() % 2) ? IDX_SORTINDICATORUP : IDX_SORTINDICATORDOWN;
  2920.  
  2921.     UINT dwDTFormat = DT_NOCLIP | DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER;
  2922.     RECT rectText = rect;
  2923.     rectText.left += 4;
  2924.     rectText.right -= 5;
  2925.  
  2926.     rectText.right -= 22;
  2927.     m_pIImage->DrawTransImage( idxImage,
  2928.                                rectText.right + 4,
  2929.                                (rect.top + rect.bottom) / 2 - 4,
  2930.                                &dc );
  2931.  
  2932.     WFE_DrawTextEx( 0, dc.m_hDC, (LPTSTR) text, -1, 
  2933.                     &rectText, dwDTFormat, WFE_DT_CROPRIGHT );
  2934.  
  2935.     return TRUE;
  2936. }
  2937.  
  2938. BOOL CRDFOutlinerParent::ColumnCommand( int iColumn )
  2939. {    
  2940.     CRDFOutliner *pOutliner = (CRDFOutliner *)m_pOutliner;
  2941.     
  2942.     int enSortType = pOutliner->GetSortType();
  2943.     if (pOutliner->GetSortColumn() != iColumn)
  2944.     {
  2945.         // May need to resort in back end (not sure)
  2946.         enSortType = HT_NO_SORT;
  2947.     }
  2948.  
  2949.     if (enSortType == HT_SORT_ASCENDING)
  2950.         enSortType = HT_SORT_DESCENDING;
  2951.     else if (enSortType == HT_SORT_DESCENDING)
  2952.         enSortType = HT_NO_SORT;
  2953.     else enSortType = HT_SORT_ASCENDING;
  2954.  
  2955.     pOutliner->SetSortType( enSortType );
  2956.     
  2957.     if (enSortType == HT_NO_SORT)
  2958.         pOutliner->SetSortColumn(-1);
  2959.     else pOutliner->SetSortColumn( iColumn );
  2960.      
  2961.     CRDFColumn* theColumn = (CRDFColumn*)(columnMap.GetCommand(iColumn));
  2962.         
  2963.     BOOL sort = TRUE;
  2964.     if (enSortType == HT_SORT_ASCENDING)
  2965.         sort = FALSE;
  2966.  
  2967.     pOutliner->SetSelectedColumn(pOutliner->m_pColumn[ iColumn ]->iCommand);
  2968.  
  2969.     Invalidate();
  2970.  
  2971.     HT_SetSortColumn(pOutliner->GetHTView(), 
  2972.                      enSortType == HT_NO_SORT ? NULL : theColumn->GetToken(), 
  2973.                      theColumn->GetDataType(), (PRBool)sort);
  2974.     
  2975.     return TRUE;
  2976. }
  2977.  
  2978. void CRDFOutlinerParent::Initialize()
  2979. {
  2980.     CreateColumns ( );
  2981.  
  2982.     CRDFOutliner* theOutliner = (CRDFOutliner*)m_pOutliner;
  2983.     m_pOutliner->SetTotalLines( HT_GetItemListCount(theOutliner->GetHTView()) );
  2984. }
  2985.  
  2986. // =======================================================================
  2987. // RDFEditWnd - Class that controls the in-place editing of column values
  2988. // =======================================================================
  2989.  
  2990. BOOL CRDFEditWnd::PreTranslateMessage ( MSG * msg )
  2991. {
  2992.    if ( msg->message == WM_KEYDOWN)
  2993.    {
  2994.       switch(msg->wParam)
  2995.       {
  2996.          case VK_RETURN:
  2997.          {
  2998.             m_pOwner->EditTextChanged(m_pOwner->GetTextEditText());
  2999.             m_pOwner->RemoveTextEdit();
  3000.             return TRUE;
  3001.  
  3002.          }
  3003.          case VK_ESCAPE:
  3004.              m_pOwner->RemoveTextEdit();
  3005.              break;
  3006.          case VK_TAB:
  3007.              m_pOwner->EditTextChanged(m_pOwner->GetTextEditText());
  3008.              m_pOwner->MoveToNextColumn();
  3009.              return TRUE;
  3010.       }
  3011.    }
  3012.    
  3013.    return CEdit::PreTranslateMessage ( msg );
  3014. }
  3015.  
  3016. //////////////////////////////////////////////////////////////////////////
  3017. //                    Messages for CRDFEditWnd
  3018. //////////////////////////////////////////////////////////////////////////
  3019.  
  3020. BEGIN_MESSAGE_MAP(CRDFEditWnd, CEdit)
  3021.     //{{AFX_MSG_MAP(CWnd)
  3022.      ON_WM_DESTROY()
  3023.     ON_WM_SETFOCUS()
  3024.     ON_WM_KILLFOCUS()
  3025.     //}}AFX_MSG_MAP
  3026. END_MESSAGE_MAP()
  3027.  
  3028. void CRDFEditWnd::OnDestroy( )
  3029. {
  3030.     delete this;
  3031.  
  3032. }
  3033.   
  3034. void CRDFEditWnd::OnSetFocus(CWnd* pOldWnd)
  3035. {
  3036.     CEdit::OnSetFocus(pOldWnd);
  3037. }
  3038.  
  3039. void CRDFEditWnd::OnKillFocus( CWnd* pNewWnd )
  3040. {
  3041.     CEdit::OnKillFocus(pNewWnd);
  3042.     m_pOwner->FocusCheck(pNewWnd, FALSE);
  3043.     m_pOwner->RemoveTextEdit(); 
  3044. }
  3045.  
  3046. // =========================================================================
  3047. // RDF Content View
  3048. IMPLEMENT_DYNAMIC(CRDFContentView, CContentView)
  3049. BEGIN_MESSAGE_MAP(CRDFContentView, CContentView)
  3050.     //{{AFX_MSG_MAP(CMainFrame)
  3051.         // NOTE - the ClassWizard will add and remove mapping macros here.
  3052.         //    DO NOT EDIT what you see in these blocks of generated code !
  3053.     ON_MESSAGE(WM_NAVCENTER_QUERYPOSITION, OnNavCenterQueryPosition)
  3054.     ON_WM_CREATE()
  3055.     ON_WM_SIZE()
  3056.     ON_WM_SETFOCUS()
  3057.     //}}AFX_MSG_MAP
  3058. END_MESSAGE_MAP()
  3059.  
  3060. LRESULT CRDFContentView::OnNavCenterQueryPosition(WPARAM wParam, LPARAM lParam)
  3061. {
  3062.     NAVCENTPOS *pPos = (NAVCENTPOS *)lParam;
  3063.     
  3064.     //  We like being in the middle.
  3065.     pPos->m_iYDisposition = 0;
  3066.     
  3067.     //  We like being this many units in size.
  3068.     pPos->m_iYVector = 200;
  3069.     
  3070.     //  Handled.
  3071.     return(NULL);
  3072. }
  3073.  
  3074. BOOL CRDFContentView::PreCreateWindow(CREATESTRUCT& cs)
  3075. {
  3076.     cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
  3077.  
  3078.     return CContentView::PreCreateWindow(cs);
  3079. }
  3080.  
  3081. void CRDFContentView::OnDraw ( CDC * pDC )
  3082. {
  3083. }
  3084.  
  3085. int CRDFContentView::OnCreate ( LPCREATESTRUCT lpCreateStruct )
  3086. {
  3087.     int iRetVal = CContentView::OnCreate ( lpCreateStruct );
  3088.     LPCTSTR lpszClass = AfxRegisterWndClass( CS_VREDRAW, ::LoadCursor(NULL, IDC_ARROW));
  3089.     m_pOutlinerParent->Create( lpszClass, _T("NSOutlinerParent"), 
  3090.                                WS_VISIBLE|WS_CHILD|WS_CLIPCHILDREN,
  3091.                                CRect(0,0,100,100), this, 101 );
  3092.     return iRetVal;
  3093. }
  3094.  
  3095. void CRDFContentView::OnSize ( UINT nType, int cx, int cy )
  3096. {
  3097.     CView::OnSize ( nType, cx, cy );
  3098.     if (IsWindow(m_pOutlinerParent->m_hWnd)) 
  3099.     {
  3100.         m_pOutlinerParent->MoveWindow ( 0, 0, cx, cy );
  3101.     }
  3102. }
  3103.  
  3104. void CRDFContentView::InvalidateOutlinerParent()
  3105. {
  3106. //    COutliner* outliner = m_pOutlinerParent->GetOutliner();
  3107. //    outliner->SqueezeColumns(-1, 0, TRUE);
  3108. }
  3109.  
  3110. void CRDFContentView::OnSetFocus ( CWnd * pOldWnd )
  3111. {
  3112.    m_pOutlinerParent->SetFocus ( );
  3113. }
  3114.  
  3115. // Functionality for the RDF Tree Embedded in HTML (Added 3/10/98 by Dave Hyatt).
  3116.  
  3117. // The event handler.  Only cares about tree events, so we'll just pass everything to the
  3118. // tree view.
  3119. void embeddedTreeNotifyProcedure (HT_Notification ns, HT_Resource n, HT_Event whatHappened) 
  3120. {
  3121.     CRDFOutliner* theOutliner = (CRDFOutliner*)HT_GetViewFEData(HT_GetView(n));
  3122.     if (theOutliner)
  3123.         theOutliner->HandleEvent(ns, n, whatHappened);
  3124. }
  3125.  
  3126. void CRDFContentView::DisplayRDFTree(CWnd* pParent, int width, int height, RDF_Resource rdfResource)
  3127. {
  3128.     HT_Notification ns = new HT_NotificationStruct;
  3129.     ns->notifyProc = embeddedTreeNotifyProcedure;
  3130.     ns->data = NULL;
  3131.     
  3132.     // Construct the pane and give it our notification struct
  3133.     HT_Pane thePane = HT_PaneFromResource(rdfResource, ns, PR_FALSE);
  3134.     
  3135.     // Build our FE windows.
  3136.     CRDFOutlinerParent* newParent = new CRDFOutlinerParent(thePane, HT_GetSelectedView(thePane));
  3137.     CRDFContentView* newView = new CRDFContentView(newParent);
  3138.  
  3139.     // Create the windows
  3140.     CRect rClient(0, 0, width, height);
  3141.     newView->Create( NULL, "", WS_CHILD | WS_VISIBLE, rClient, pParent, NC_IDW_OUTLINER);
  3142.  
  3143.     // Initialize the columns, etc.
  3144.     newParent->Initialize();
  3145.  
  3146.     // Set our FE data to be the outliner.
  3147.     HT_SetViewFEData(HT_GetSelectedView(thePane), newParent->GetOutliner());
  3148. }
  3149.  
  3150. // Function to grab an RDF context
  3151.  
  3152. extern "C" MWContext* FE_GetRDFContext(void) 
  3153. {
  3154.     MWContext *pRetval = NULL;
  3155.     
  3156.     if(theApp.m_pRDFCX) 
  3157.     {
  3158.         pRetval = theApp.m_pRDFCX->GetContext();
  3159.     }
  3160.     
  3161.     return(pRetval);
  3162. }
  3163.  
  3164.  
  3165. // The context's GetDialogOwner() function.
  3166. CWnd* CRDFCX::GetDialogOwner() const
  3167. {
  3168.     if (m_pCurrentRDFWindow == NULL)
  3169.         return CWnd::GetDesktopWindow();
  3170.     return m_pCurrentRDFWindow->GetTopLevelFrame();
  3171. }
  3172.  
  3173.  
  3174. /////////////////////////////////////////////////////////////////////////////
  3175. /////////////////////////////////////////////////////////////////////////////
  3176. /////////////////////////////////////////////////////////////////////////////
  3177. // CDialogPRMT dialog
  3178.  
  3179. void stdPrint (void* data, char* str) {
  3180.   fprintf((FILE*)data, str);
  3181. }
  3182.  
  3183. CExportRDF::CExportRDF(CWnd* pParent /*=NULL*/)
  3184.     : CDialog(CExportRDF::IDD, pParent)
  3185. {
  3186.     m_csTitle = _T("");
  3187.     
  3188.     //{{AFX_DATA_INIT(CDialogPRMT)
  3189.     m_csAns = "";
  3190.     //}}AFX_DATA_INIT
  3191. }
  3192.  
  3193. void CExportRDF::DoDataExchange(CDataExchange* pDX)
  3194. {
  3195.     CDialog::DoDataExchange(pDX);
  3196.     //{{AFX_DATA_MAP(CDialogPRMT)
  3197.     DDX_Text(pDX, IDC_PROMPT_ANS, m_csAns);
  3198.     //}}AFX_DATA_MAP
  3199. }
  3200.  
  3201. BEGIN_MESSAGE_MAP(CExportRDF, CDialog)
  3202.     //{{AFX_MSG_MAP(CDialogPRMT)
  3203.         // NOTE: the ClassWizard will add message map macros here
  3204.     //}}AFX_MSG_MAP
  3205. END_MESSAGE_MAP()
  3206.