home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / winfe / outliner.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  96.6 KB  |  3,989 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. #include "stdafx.h"
  20. #include "outliner.h"
  21. #include "imagemap.h"
  22. #include "prefapi.h"
  23. #include "tip.h"
  24. #include "fegui.h"
  25. #ifdef _WIN32
  26. #include "intelli.h"
  27. #endif
  28.  
  29. #include "qahook.h"        // rhp - added for QA Partner automated testing messages
  30.  
  31. #define COL_LEFT_MARGIN    ((m_cxChar+1)/2)
  32. #define OUTLINE_TEXT_OFFSET 8
  33.  
  34. #define ID_OUTLINER_HEARTBEAT    2
  35. #define ID_OUTLINER_TIMER       3
  36. #define ID_OUTLINER_TIMER_DELAY 500
  37.  
  38. #define OUTLINER_PERCENTFACTOR 10000
  39. #ifndef _AFXDLL
  40. #undef new
  41. #endif
  42. IMPLEMENT_DYNCREATE(COutlinerView, CView)
  43. #ifndef _AFXDLL
  44. #define new DEBUG_NEW
  45. #endif
  46.  
  47. #ifndef _WIN32
  48. HGDIOBJ GetCurrentObject(HDC hdc, UINT uObjectType)
  49. {
  50.     HGDIOBJ res = NULL;
  51.     switch (uObjectType) {
  52.     case OBJ_BRUSH:
  53.         res = ::SelectObject(hdc, GetStockObject(NULL_BRUSH));
  54.         ::SelectObject(hdc, res);
  55.         break;
  56.     case OBJ_PEN:
  57.         res = ::SelectObject(hdc, GetStockObject(NULL_PEN));
  58.         ::SelectObject(hdc, res);
  59.         break;
  60.     default:
  61.         break;
  62.     }
  63.     return res;
  64. }
  65. #endif
  66.  
  67.  
  68. //////////////////////////////////////////////////////////////////////////////
  69. // COutliner
  70.  
  71. BOOL COutliner::m_bTipsEnabled = TRUE;
  72.  
  73. #define TIP_WAITING    1
  74. #define TIP_SHOWING    2
  75. #define TIP_SHOWN    3
  76. #define TIP_HEARTBEAT    100
  77. #define TIP_DELAY        250
  78.  
  79. #define DRAG_HEARTBEAT    250
  80.  
  81. BEGIN_MESSAGE_MAP(COutliner, CWnd)
  82.     ON_WM_SETCURSOR ( )
  83.     ON_WM_CREATE ( )
  84.     ON_WM_PAINT ( )
  85.     ON_WM_SIZE ( )
  86.     ON_WM_GETMINMAXINFO ( )
  87.     ON_WM_DESTROY ( )
  88.     ON_WM_LBUTTONDOWN ( )
  89.     ON_WM_MOUSEMOVE()
  90.     ON_WM_LBUTTONUP()
  91.     ON_WM_RBUTTONDOWN ( )
  92.     ON_WM_RBUTTONUP()
  93.     ON_WM_VSCROLL ( )
  94.     ON_WM_SETFOCUS ( )
  95.     ON_WM_KILLFOCUS ( )
  96.     ON_WM_SYSKEYDOWN()
  97.     ON_WM_KEYDOWN ( )
  98.     ON_WM_KEYUP()
  99.     ON_WM_LBUTTONDBLCLK ( )
  100.     ON_WM_ERASEBKGND ( )
  101.     ON_WM_TIMER ( )
  102.     ON_WM_SYSCOLORCHANGE ( )
  103.     ON_WM_GETDLGCODE()
  104. #if defined(XP_WIN32) && _MSC_VER >= 1100
  105.     ON_REGISTERED_MESSAGE(msg_MouseWheel, OnHackedMouseWheel)
  106.     ON_MESSAGE(WM_MOUSEWHEEL, OnMouseWheel)
  107. #endif
  108.  
  109.     // rhp - For QA partner message handling
  110.     ON_MESSAGE(WM_COPYDATA, OnProcessOLQAHook)
  111.     // rhp
  112.  
  113. END_MESSAGE_MAP()
  114.  
  115. class CNSOutlinerFactory :  public  CGenericFactory
  116. {
  117. public:
  118.     CNSOutlinerFactory();
  119.     ~CNSOutlinerFactory();
  120.     STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter,REFIID refiid, LPVOID * ppvObj);
  121. };
  122.  
  123. CNSOutlinerFactory::CNSOutlinerFactory()
  124. {
  125.    ApiApiPtr(api);
  126.     api->RegisterClassFactory(APICLASS_OUTLINER,this);
  127. }
  128.  
  129. CNSOutlinerFactory::~CNSOutlinerFactory()
  130. {
  131. }
  132.  
  133. STDMETHODIMP CNSOutlinerFactory::CreateInstance(
  134.     LPUNKNOWN pUnkOuter,
  135.     REFIID refiid,
  136.     LPVOID * ppvObj)
  137. {
  138.     COutliner * pOutliner = new COutliner;
  139.     *ppvObj = (LPVOID)((LPUNKNOWN)pOutliner);
  140.     return NOERROR;
  141. }
  142.  
  143. DECLARE_FACTORY(CNSOutlinerFactory);
  144.  
  145. COutliner::COutliner ( )
  146. {
  147. #ifdef _WIN32
  148.     m_iWheelDelta = 0;
  149. #endif
  150.     m_iDragSelection = -1;
  151.     m_iDragSelectionLineHalf = -1;
  152.     m_iDragSelectionLineThird = -1;
  153.     m_bDragSectionChanged = FALSE;
  154.     m_iLastSelected = -1;
  155.     m_iTotalLines   = 0;
  156.     m_iTopLine      = 0;
  157.     m_iSelection    = -1;
  158.     m_iFocus        = -1;
  159.     m_pColumn       = NULL;
  160.     m_iNumColumns   = 0;
  161.     m_iVisColumns    = 0;
  162.     m_iTotalWidth    = 0;
  163.     m_idImageCol    = 0;
  164.     m_bHasPipes        = TRUE;
  165.     m_pDropTarget   = NULL;
  166.     m_bDraggingData = FALSE;
  167.     m_bClearOnRelease = FALSE;
  168.     m_bSelectOnRelease = FALSE;
  169.     
  170.     m_pTip = new CTip();
  171.     m_pTip->Create();
  172.  
  173.     m_iTipState = 0;
  174.     m_iTipTimer = 0;
  175.     m_iTipRow = m_iTipCol = -1;
  176.  
  177.     m_hBoldFont = NULL;
  178.     m_hRegFont = NULL;
  179.     m_hItalFont = NULL;
  180.  
  181.     m_pUnkImage = NULL;
  182.     ApiApiPtr(api);
  183.     m_pUnkImage = api->CreateClassInstance(
  184.         APICLASS_IMAGEMAP,NULL,(APISIGNATURE)GetOutlinerBitmap());
  185.     m_pUnkImage->QueryInterface(IID_IImageMap,(LPVOID*)&m_pIImage);
  186.     ASSERT(m_pIImage);
  187.     if (!m_pIImage->GetResourceID())
  188.         m_pIImage->Initialize(GetOutlinerBitmap(),16,16);
  189. }
  190.  
  191. COutliner::~COutliner ( )
  192. {
  193.     if(m_pDropTarget) {
  194.         m_pDropTarget->Revoke();
  195.         delete m_pDropTarget;
  196.         m_pDropTarget = NULL;
  197.     }
  198.  
  199.     if (m_pUnkImage) {
  200.         if (m_pIImage)
  201.             m_pUnkImage->Release();
  202.     }
  203.  
  204.     if ( m_pColumn )
  205.     {
  206.         while ( m_iNumColumns )
  207.         {
  208.             if (m_pColumn[ m_iNumColumns - 1]->pHeader)
  209.                 free((char*)m_pColumn[ m_iNumColumns - 1]->pHeader);
  210.             delete(m_pColumn[ m_iNumColumns - 1 ]);
  211.             m_iNumColumns--;
  212.         }
  213.         free(m_pColumn);
  214.     }
  215.     if (m_hBoldFont) {
  216.         theApp.ReleaseAppFont(m_hBoldFont);
  217.     }
  218.     if (m_hRegFont) {
  219.         theApp.ReleaseAppFont(m_hRegFont);
  220.     }
  221.     if (m_hItalFont) {
  222.         theApp.ReleaseAppFont(m_hItalFont);
  223.     }
  224.  
  225.     delete m_pTip;
  226. }
  227.  
  228. STDMETHODIMP COutliner::QueryInterface(
  229.    REFIID refiid,
  230.    LPVOID * ppv)
  231. {
  232.     *ppv = NULL;
  233.  
  234.     if (IsEqualIID(refiid,IID_IOutliner))
  235.         *ppv = (LPIOUTLINER) this;
  236.  
  237.     if (*ppv != NULL) {
  238.          AddRef();
  239.          return NOERROR;
  240.     }
  241.  
  242.     return CGenericObject::QueryInterface(refiid,ppv);
  243. }
  244.  
  245. void COutliner::OnDestroy()
  246. {
  247.     if (m_iTipTimer) {
  248.         KillTimer(m_iTipTimer);
  249.         m_iTipTimer = 0;
  250.     }
  251.     TipHide();
  252. }
  253.  
  254. void COutliner::TipHide()
  255. {
  256.     if (m_iTipTimer) {
  257.         KillTimer(m_iTipTimer);
  258.         m_iTipTimer = 0;
  259.     }
  260.     m_pTip->Hide();
  261.     m_iTipState = TIP_SHOWN;
  262. }
  263.  
  264. void COutliner::EnableTips(BOOL s)
  265. {
  266.     TipHide();
  267.     m_iTipState = 0;
  268.     m_bTipsEnabled = s;
  269. }
  270.  
  271. BOOL COutliner::TestRowCol(POINT point, int &iRow, int &iCol)
  272. {
  273.     RECT rcClient;
  274.     GetClientRect(&rcClient);
  275.  
  276.     if (::PtInRect(&rcClient, point)) {
  277.         void *pLineData = NULL;
  278.         int iSel = point.y  / m_itemHeight;
  279.         int iNewSel = m_iTopLine + iSel;
  280.         if ( ( pLineData = AcquireLineData ( iNewSel ) ) != NULL ) {
  281.             ReleaseLineData( pLineData );
  282.             int i, offset;
  283.             int y = iSel * m_itemHeight;
  284.  
  285.             for ( i = 0, offset = 0; i < m_iVisColumns; i++ )
  286.             {
  287.                 CRect rect ( offset, y,
  288.                              offset + m_pColumn[ i ]->iCol, y + m_itemHeight );
  289.  
  290.                 if ( rect.PtInRect(point) ) 
  291.                 {
  292.                     iRow = iNewSel;
  293.                     iCol = i;
  294.                     m_rcHit = rect;
  295.  
  296.                     return TRUE;
  297.                 }
  298.                 offset += m_pColumn[ i ]->iCol;
  299.             }
  300.         }
  301.     }
  302.     return FALSE;
  303. }
  304.  
  305. UINT COutliner::GetOutlinerBitmap(void)
  306. {
  307.     return IDB_OUTLINER;
  308. }
  309.  
  310. BOOL COutliner::OnEraseBkgnd( CDC * )
  311. {
  312.     return TRUE;
  313. }
  314.  
  315. int COutliner::GetColumnSize ( UINT idCol )
  316. {
  317.  
  318.     if ( m_pColumn )
  319.         for ( int iColumn = 0; iColumn < m_iNumColumns; iColumn++ )    
  320.             if ( m_pColumn[ iColumn ]->iCommand == idCol )
  321.                 return m_pColumn[ iColumn ]->iCol;
  322.     return 0;
  323. }
  324.  
  325. int COutliner::GetColumnPercent ( UINT idCol )
  326. {
  327.     if ( m_pColumn )
  328.         for ( int iColumn = 0; iColumn < m_iNumColumns; iColumn++ )    
  329.             if ( m_pColumn[ iColumn ]->iCommand == idCol )
  330.                 return (int)(m_pColumn[ iColumn ]->fPercent * OUTLINER_PERCENTFACTOR);
  331.     return 0;
  332. }
  333.  
  334. int COutliner::GetColumnPos ( UINT idCol )
  335. {
  336.     if ( m_pColumn )
  337.         for ( int iColumn = 0; iColumn < m_iNumColumns; iColumn++ )
  338.             if ( m_pColumn[ iColumn ]->iCommand == idCol )
  339.                 return iColumn;
  340.     return -1;
  341. }
  342.  
  343. UINT COutliner::GetColumnAtPos ( int iPos )
  344. {
  345.     if ( m_pColumn )
  346.         if (iPos >= 0 && iPos < m_iNumColumns)
  347.             return m_pColumn[ iPos ]->iCommand;
  348.  
  349.     return 0;
  350. }
  351.  
  352. int COutliner::AddColumn ( 
  353.     LPCTSTR header, UINT command,
  354.     int iMinCol, int iMaxCol, 
  355.     Column_t ColType, 
  356.     int iPercent, 
  357.     BOOL bButton,
  358.     CropType_t ct, AlignType_t at )
  359. {
  360.     OutlinerColumn_t * pColumn = new OutlinerColumn_t;
  361.     pColumn->pHeader = _tcsdup(header);
  362.     pColumn->cType = ColType;
  363.     pColumn->bIsButton = bButton;
  364.     pColumn->iMinColSize = iMinCol;
  365.     pColumn->iMaxColSize = iMaxCol;
  366.     pColumn->fPercent = (FLOAT)((FLOAT)iPercent/(FLOAT)OUTLINER_PERCENTFACTOR);
  367.     pColumn->fDesiredPercent = pColumn->fPercent;
  368.     pColumn->iCol =  iMinCol;
  369.     pColumn->bDepressed = 0;
  370.     pColumn->iCommand = command;
  371.     pColumn->cropping = ct;
  372.     pColumn->alignment = at;
  373.     if ( !m_pColumn )
  374.         m_pColumn = (OutlinerColumn_t **)malloc(sizeof(OutlinerColumn_t *));
  375.     else
  376.         m_pColumn = (OutlinerColumn_t **)realloc(m_pColumn,sizeof(OutlinerColumn_t*)*(m_iNumColumns+1));
  377.     m_pColumn[ m_iNumColumns ] = pColumn;
  378.     m_iVisColumns = ++m_iNumColumns;
  379.  
  380.     return m_iNumColumns;
  381. }
  382.  
  383. void COutliner::SetColumnPos ( UINT idCol, int iColumn ) {
  384.     int iOldColumn;
  385.  
  386.     iOldColumn = GetColumnPos(idCol);
  387.     
  388.     if ( (iOldColumn < 0) || (iColumn >= m_iNumColumns) || (iColumn < 0) )
  389.         return;
  390.  
  391.     OutlinerColumn_t *temp;
  392.     temp = m_pColumn[ iColumn ];
  393.     m_pColumn[ iColumn ] = m_pColumn[ iOldColumn ];
  394.     m_pColumn[ iOldColumn ] = temp;
  395.  
  396.     Invalidate ( );
  397. }
  398.  
  399. void COutliner::SetColumnName ( UINT idCol, LPCTSTR pName )
  400. {
  401.     int iColumn;
  402.     if ( ( iColumn = GetColumnPos( idCol ) ) < 0 )
  403.         return;
  404.  
  405.     if (m_pColumn[ iColumn ]->pHeader)
  406.         free((char*)m_pColumn[ iColumn ]->pHeader);
  407.     m_pColumn[ iColumn ]->pHeader = _tcsdup(pName);
  408. }
  409.  
  410. void COutliner::SetColumnSize ( UINT idCol, int iSize )
  411. {
  412.     int iColumn;
  413.     if ( ( iColumn = GetColumnPos( idCol ) ) < 0 )
  414.         return;
  415.  
  416.     m_pColumn[ iColumn ]->iCol = iSize;
  417. }
  418.  
  419. void COutliner::SetColumnPercent ( UINT idCol, int iPercent )
  420. {
  421.     int iColumn;
  422.     if ( ( iColumn = GetColumnPos( idCol ) ) < 0 )
  423.         return;
  424.  
  425.     m_pColumn[ iColumn ]->fPercent = m_pColumn[iColumn]->fDesiredPercent = (FLOAT)((FLOAT)iPercent/(FLOAT)OUTLINER_PERCENTFACTOR);
  426. }
  427.  
  428. void COutliner::LoadXPPrefs( const char *prefname )
  429. {
  430.     int i, j;
  431.     
  432.     char buf[256];
  433.     char *formatString = buf;
  434.     int iLen = 256;
  435.     memset(formatString, 0, 256);
  436.     PREF_GetCharPref(prefname, formatString, &iLen);
  437.     char *end = formatString + iLen;
  438.  
  439.     if ( formatString[0] == 'v' && formatString[1] == '1') {
  440.         formatString += 2;
  441.     } else {
  442.         return;
  443.     }
  444.  
  445.     i = 0;
  446.     j = 0;
  447.  
  448.     int nVis;
  449.     if (sscanf(formatString, " %d %n", &nVis, &j) ==  1) {
  450.         formatString += j;
  451.     } else {
  452.         return;
  453.     }
  454.  
  455.     while (formatString < end && formatString[0]) {
  456.         int id, nWidth;
  457.  
  458.         if (sscanf(formatString, " %d : %d %n", &id, &nWidth, &j) == 2) {
  459.  
  460.             // We should really check these values in case 
  461.             // someone mucks with their registry.
  462.  
  463.             SetColumnPos( id, i );
  464.             SetColumnPercent( id, nWidth );
  465.  
  466.             formatString += j;
  467.             i++;
  468.         } else {
  469.             break;
  470.         }
  471.     }
  472.  
  473.     SetVisibleColumns( nVis );
  474.  
  475.     // Make it so
  476.     RECT rcClient;
  477.     GetClientRect(&rcClient);
  478.     OnSize(0, rcClient.right, rcClient.bottom);
  479.  
  480.     GetParent()->Invalidate();
  481. }
  482.  
  483. void COutliner::SaveXPPrefs( const char *prefname )
  484. {
  485.     CString cs, cs2;
  486.  
  487.     cs = "v1";
  488.     cs2.Format(" %d", GetVisibleColumns());
  489.     cs += cs2; 
  490.     for (int i = 0; i < m_iNumColumns; i++) {
  491.         cs2.Format(_T(" %d:%d"), 
  492.                    GetColumnAtPos(i),
  493.                    GetColumnPercent(GetColumnAtPos(i)));
  494.         cs += cs2;
  495.     }
  496.  
  497.     PREF_SetCharPref( prefname, cs );
  498. }
  499.  
  500. void COutliner::OnSize( UINT nType, int cx, int cy )
  501. {
  502.     SqueezeColumns( -1, 0, FALSE );
  503.     m_iPaintLines = ( cy / m_itemHeight ) + 1;
  504.     EnableScrollBars ( );
  505. }
  506.  
  507. void COutliner::OnGetMinMaxInfo ( MINMAXINFO FAR* lpMMI )
  508. {
  509.     CWnd::OnGetMinMaxInfo( lpMMI );
  510.     int max = 0, min = 0;
  511.     int i;
  512.  
  513.     for ( i = 0; i < m_iVisColumns; i++ ) {
  514.         if (max >= 0) {
  515.             if (m_pColumn[ i ]->iMaxColSize > 0) {
  516.                 max += m_pColumn[ i ]->iMaxColSize;
  517.             } else {
  518.                 max = -1;
  519.             }
  520.         }
  521.         if (min >= 0) {
  522.             if (m_pColumn[ i ]->iMinColSize > 0) {
  523.                 min += m_pColumn[ i ]->iMinColSize;
  524.             }
  525.         }
  526.     }
  527.     if (max >= 0) {
  528.         lpMMI->ptMaxSize.x;
  529.         lpMMI->ptMaxTrackSize.x;
  530.     }
  531.     if (min >= 0) {
  532.         lpMMI->ptMinTrackSize.x;
  533.     }
  534. }
  535.  
  536. //------------------------------------------------------------------------------
  537. // 
  538. // Sizes variable width columns to fit the current width of the outliner.
  539. // 
  540. // iColFrom:  -1 implies all columns will size to fit.
  541. //             0+ implies the column is sizing and all following columns will size to fit.
  542. //
  543. // iDelta:    Specifies the delta for the size.  If 0, all columns adjust to size.
  544. //
  545. // bRepaint:  Repaint all the affected columns after the size.
  546. //
  547. BOOL COutliner::SqueezeColumns( int iColFrom /*=-1*/, int iDelta /*=0*/, BOOL bRepaint /*=TRUE*/ )
  548. {
  549.     ASSERT( iColFrom >= -1 );
  550.     
  551.     if( m_iVisColumns == 0 )
  552.     {
  553.         return FALSE;
  554.     }
  555.  
  556.     ASSERT( iColFrom < m_iVisColumns );
  557.         
  558.     if( (iColFrom != -1) && (iDelta == 0) )
  559.     {
  560.         return FALSE;
  561.     }
  562.  
  563.     CFont *pOldFont = NULL;
  564.     CDC *pDC = GetDC();
  565.     if( GetFont() ) 
  566.     {
  567.         pOldFont = pDC->SelectObject( GetFont() );
  568.     }
  569.     CSize csMinWidth = pDC->GetTextExtent( "W", _tcslen( "W" ) );
  570.     if( pOldFont ) 
  571.     {
  572.         pDC->SelectObject( pOldFont );
  573.     }
  574.     ReleaseDC( pDC );
  575.     
  576.     //
  577.     // Calculate variable column width and percent
  578.     //
  579.     LONG iVariableWidth        = m_iTotalWidth;    
  580.     LONG iActualVariableWidth  = 0;
  581.     FLOAT fDesiredVariablePercent = (FLOAT)0;    
  582.     int iOldRightWidth         = 0;
  583.     LONG iActualTotalWidth     = 0;
  584.     BOOL bResetPercents        = FALSE;
  585.     int i;
  586.     int iMinLeftWidth = 0;
  587.     for( i = 0; i < m_iVisColumns; i++ )
  588.     {
  589.         if( m_pColumn[i]->cType == ColumnVariable )
  590.         {
  591.             if( i <= iColFrom )
  592.             {
  593.                 iOldRightWidth += m_pColumn[i]->iCol;
  594.             }
  595.             else
  596.             {
  597.                 if( bResetPercents || (m_pColumn[i]->fPercent == m_pColumn[i]->fDesiredPercent) )
  598.                 {
  599.                     bResetPercents = TRUE;
  600.                     
  601.                     m_pColumn[i]->fDesiredPercent = m_pColumn[i]->fPercent;
  602.                 }
  603.                 iMinLeftWidth += csMinWidth.cx; //max( m_pColumn[i]->iMinColSize, csMinWidth.cx );
  604.             }
  605.             
  606.             fDesiredVariablePercent += m_pColumn[i]->fDesiredPercent;            
  607.             
  608.             // Only used when iDelta is not specified and is calculated e.g., during window size
  609.             iActualVariableWidth += m_pColumn[i]->iCol;
  610.         } 
  611.         else 
  612.         {
  613.             if( i > iColFrom )
  614.             {
  615.                 iMinLeftWidth += m_pColumn[i]->iCol;
  616.             }
  617.         
  618.             iVariableWidth -= m_pColumn[i]->iCol;
  619.         }
  620.         
  621.         iActualTotalWidth += m_pColumn[i]->iCol;
  622.     }
  623.     
  624.     if( (iColFrom == -1) && (iDelta == 0) )
  625.     {
  626.         //
  627.         // We must calculate the delta when iColFrom is -1.  Most likely the outliner's window
  628.         // has changed size.
  629.         //
  630.         iDelta = CASTINT(iActualTotalWidth - m_iTotalWidth);
  631.     }
  632.  
  633.     if( iVariableWidth < 0 ) 
  634.     {
  635.         return FALSE;
  636.     }
  637.  
  638.     LONG iSurplus = iVariableWidth;
  639.     
  640.     if( fDesiredVariablePercent == 0 ) 
  641.     {
  642.         return FALSE;
  643.     }
  644.  
  645.     //
  646.     // Calculate the smallest allowable variable column width and percent
  647.     //
  648.     FLOAT fMinPercent = (FLOAT)csMinWidth.cx/(FLOAT)iVariableWidth;
  649.     
  650.     if( (iColFrom != -1) && (iDelta < 0) && (m_pColumn[iColFrom]->fPercent <= fMinPercent) )
  651.     {
  652.         // Can't size it any smaller
  653.         return FALSE;
  654.     }
  655.     
  656.     int iNewLeftWidth = 0;
  657.     
  658.     //
  659.     // Enforce the delta limit for left sizing
  660.     //
  661.     if( (iColFrom != -1) && ((m_pColumn[iColFrom]->iCol + iDelta) <= csMinWidth.cx) )
  662.     {
  663.         iDelta = m_pColumn[iColFrom]->iCol - csMinWidth.cx;
  664.     }
  665.     
  666.     //
  667.     // Enforce the delta limit for right sizing
  668.     //
  669.     int iNumLeftCols = (m_iVisColumns - iColFrom) - 1;
  670.     int iNewRightWidth = iOldRightWidth + iDelta;
  671.     iMinLeftWidth = iNumLeftCols * csMinWidth.cx;
  672.     
  673.     iNewLeftWidth = CASTINT(((iColFrom == -1) ? iActualVariableWidth : iVariableWidth) - iNewRightWidth);
  674.     
  675.     BOOL bSign = (iDelta > 0);
  676.     
  677.     if( iNewLeftWidth < iMinLeftWidth )
  678.     {
  679.         iDelta -= (iMinLeftWidth - iNewLeftWidth);
  680.         iNewLeftWidth = CASTINT(iVariableWidth - (iOldRightWidth + iDelta));
  681.         iNewRightWidth = CASTINT(iVariableWidth - iNewLeftWidth);
  682.         ASSERT( iNewRightWidth == (iOldRightWidth + iDelta) );
  683.     }
  684.     
  685.     if( iNewLeftWidth < iMinLeftWidth )
  686.     {
  687.         return FALSE;
  688.     }
  689.     
  690.     if( iDelta == 0 )
  691.     {
  692.         return FALSE;
  693.     }
  694.     
  695.     if( bSign != (iDelta > 0) )
  696.     {
  697.         // The sign should not have changed, but just to be safe...    
  698.         return FALSE;
  699.     }
  700.     
  701.     FLOAT fNewLeftPercent = (FLOAT)iNewLeftWidth/(FLOAT)iVariableWidth;
  702.  
  703.     for( i = 0; i < m_iVisColumns; i++ )
  704.     {
  705.         if( m_pColumn[i]->cType != ColumnVariable ) 
  706.         {
  707.             continue;
  708.         }
  709.  
  710.         if( i < iColFrom )    
  711.         {
  712.             // Column's to the right of the sizing column don't change, so just decrement the var percent
  713.             
  714.             fDesiredVariablePercent -= m_pColumn[i]->fDesiredPercent;            
  715.         }
  716.         else if( i == iColFrom )
  717.         {
  718.             // Decrement the percent BEFORE we calc the new percent
  719.             
  720.             fDesiredVariablePercent -= m_pColumn[i]->fDesiredPercent;            
  721.             
  722.             // Add the delta and calc the new percent
  723.                                 
  724.             m_pColumn[i]->iCol += iDelta;
  725.             m_pColumn[i]->fPercent = (FLOAT)m_pColumn[i]->iCol/(FLOAT)iVariableWidth;
  726.             m_pColumn[i]->fDesiredPercent = m_pColumn[i]->fPercent;
  727.         }
  728.         else
  729.         {
  730.             FLOAT fPrevPercent = m_pColumn[i]->fPercent;
  731.             FLOAT fPrevDesiredPercent = m_pColumn[i]->fDesiredPercent;            
  732.             
  733.             m_pColumn[i]->fPercent = fNewLeftPercent * m_pColumn[i]->fDesiredPercent/fDesiredVariablePercent;
  734.             m_pColumn[i]->fPercent = max( m_pColumn[i]->fPercent, fMinPercent );
  735.                         
  736.             m_pColumn[i]->iCol = (int)((FLOAT)iNewLeftWidth * m_pColumn[i]->fPercent/fNewLeftPercent);
  737.             m_pColumn[i]->iCol = max( m_pColumn[i]->iCol, csMinWidth.cx );
  738.         }
  739.         
  740.         iSurplus -= m_pColumn[i]->iCol;        
  741.     }
  742.  
  743.     //
  744.     // Consume the surplus space somewhat evenly
  745.     //
  746.     while( iSurplus )
  747.     {
  748.         for( i = iColFrom+1; i < m_iVisColumns; i++ )
  749.         {
  750.             if( m_pColumn[i]->cType != ColumnVariable ) 
  751.             {
  752.                 continue;
  753.             }
  754.         
  755.             if( iSurplus > 0 )
  756.             {
  757.                 m_pColumn[i]->iCol += 1;
  758.                 iSurplus--;
  759.             }
  760.             else if( m_pColumn[i]->iCol > csMinWidth.cx )
  761.             {
  762.                 m_pColumn[i]->iCol -= 1;
  763.                 iSurplus++;
  764.             }
  765.             
  766.             if( !iSurplus )
  767.             {
  768.                 break;
  769.             }
  770.         }
  771.     }
  772.         
  773.     if( !bRepaint )
  774.     {
  775.         return TRUE;
  776.     }
  777.     
  778.       for( i = iColFrom; i < m_iVisColumns; i++) 
  779.     {
  780.           InvalidateColumn( i );
  781.     }
  782.     
  783.     return TRUE;
  784. }
  785.  
  786. // iDesiredSize is what the outliner wants to be.  In this default case
  787. // we use this height.
  788. void COutliner::InitializeItemHeight(int iDesiredSize)
  789. {
  790.     m_itemHeight = iDesiredSize;
  791.  
  792. }
  793.  
  794. void COutliner::PropertyMenu( int iLine, UINT flags )
  795. {
  796. }
  797.  
  798. BOOL COutliner::ColumnCommand( int iCol, int iLine )
  799. {
  800.     return FALSE;
  801. }
  802.  
  803. void COutliner::InitializeClipFormats()
  804. {
  805. }
  806.  
  807. void COutliner::OnRButtonDown ( UINT nFlags, CPoint point )
  808. {
  809.     TipHide();
  810.     CWnd::OnRButtonDown ( nFlags, point );
  811.     m_ptHit = point;
  812.     int iSel = m_iTopLine + (point.y  / m_itemHeight);
  813.     SelectItem( iSel, OUTLINER_RBUTTONDOWN );
  814. }
  815.  
  816. void COutliner::OnRButtonUp( UINT nFlags, CPoint point )
  817. {
  818.     m_ptHit = point;
  819.     int iSel = m_iTopLine + (point.y  / m_itemHeight);
  820.     
  821.     PropertyMenu( iSel, nFlags );
  822. }
  823.  
  824. void COutliner::HandleMouseMove( POINT point )
  825. {
  826.     if (m_bTipsEnabled) {
  827.         int iRow, iCol;
  828.         CPoint ptCorner;
  829.  
  830.         // make sure the outline itself is active
  831. #ifdef _WIN32
  832.         CWnd* pParent = GetParentOwner();
  833. #else
  834.         CWnd* pParent = GetParent();
  835.         if (pParent)
  836.         {
  837.             LONG lStyle = GetWindowLong(pParent->GetSafeHwnd(), GWL_STYLE);
  838.             while ((lStyle & WS_CHILD) && (pParent = pParent->GetParent()))
  839.             {
  840.                 lStyle = GetWindowLong(pParent->GetSafeHwnd(), GWL_STYLE);
  841.             }
  842.         }
  843. #endif
  844.         if ((pParent != GetActiveWindow()) || !pParent->IsWindowEnabled()) {
  845.             TipHide();
  846.             return;
  847.         }
  848.  
  849.         // check for this application tracking (capture set)
  850.         CWnd* pCapture = GetCapture();
  851.         if (pCapture) {
  852.             TipHide();
  853.             return;
  854.         }
  855.  
  856.         if (TestRowCol(point, iRow, iCol)) {
  857.             if (( iCol != m_iTipCol) || (iRow != m_iTipRow)) {
  858.                 ASSERT(iCol < m_iNumColumns);
  859.                 ASSERT(iRow < m_iTotalLines);
  860.                 m_iTipRow = iRow;
  861.                 m_iTipCol = iCol;
  862.  
  863.                 switch (m_iTipState) {
  864.                 case 0: case TIP_WAITING:
  865.                     m_iTipTimer = SetTimer(ID_OUTLINER_HEARTBEAT, TIP_DELAY, NULL);
  866.                     break;
  867.                 case TIP_SHOWING: 
  868.                     m_pTip->Hide();
  869.                     m_iTipState = TIP_WAITING;
  870.                     m_iTipTimer = SetTimer(ID_OUTLINER_HEARTBEAT, TIP_HEARTBEAT, NULL);
  871.                     break;
  872.                 case TIP_SHOWN:
  873.                     break;
  874.                 }
  875.  
  876.             }
  877.             return;
  878.         }
  879.  
  880.         TipHide();
  881.         m_iTipCol = -1;
  882.         m_iTipRow = -1;
  883.         m_iTipState = 0;    
  884.     }
  885.     return;
  886. }
  887.  
  888. void COutliner::OnMouseMove(UINT nFlags, CPoint point)
  889. {
  890.     if (GetCapture() == this) {
  891.         // See if the mouse has moved far enough to start
  892.         // a drag operation
  893.         if ((abs(point.x - m_ptHit.x) > 3)
  894.         || (abs(point.y - m_ptHit.y) > 3)) {
  895.             // release the mouse capture
  896.             ReleaseCapture();
  897.             InitiateDragDrop();
  898.  
  899.             m_bClearOnRelease = FALSE;
  900.             m_bSelectOnRelease = FALSE;
  901.             SelectItem( m_iSelection, OUTLINER_LBUTTONUP, nFlags );
  902.         }
  903.     }
  904.     if (m_iTipState != TIP_SHOWING)
  905.         m_iTipState = TIP_WAITING;
  906.     HandleMouseMove( point );
  907. }
  908.  
  909. void COutliner::OnLButtonUp(UINT nFlags, CPoint point)
  910. {
  911.     if (GetCapture() == this) {
  912.         ReleaseCapture();
  913.         SelectItem( m_iSelection, OUTLINER_LBUTTONUP, nFlags );
  914.     }
  915. }
  916.  
  917. void COutliner::OnLButtonDown ( UINT nFlags, CPoint point )
  918. {
  919.     Default();
  920.     TipHide();
  921.  
  922.     SetFocus();
  923.  
  924.     m_ptHit = point;
  925.     
  926.     int iRow, iCol;
  927.  
  928.     if ( TestRowCol( point, iRow, iCol ) ){
  929.         m_iRowHit = iRow;
  930.         m_iColHit = iCol;
  931.  
  932.         if ( m_pColumn[ iCol ]->iCommand == m_idImageCol ) {
  933.             void * pLineData;
  934.             if ( ( pLineData = AcquireLineData ( iRow ) ) ) {
  935.                 int iDepth;
  936.                 GetTreeInfo ( iRow, NULL, &iDepth, NULL );
  937.                 ReleaseLineData ( pLineData );
  938.  
  939.                 int iImageWidth = m_pIImage->GetImageWidth ( );
  940.                 RECT rcToggle = m_rcHit;
  941.                 rcToggle.left += iDepth * iImageWidth;
  942.                 rcToggle.right = rcToggle.left + iImageWidth;
  943.  
  944.                 if ( ::PtInRect( &rcToggle, point ) ) {
  945.                     DoToggleExpansion ( iRow );
  946.                     return;
  947.                 }
  948.             }
  949.         }
  950.         if ( ColumnCommand( m_pColumn[ iCol ]->iCommand, iRow) )
  951.             return;
  952.  
  953.         SetCapture();
  954.         SelectItem( iRow, OUTLINER_LBUTTONDOWN, nFlags );
  955.     }
  956. }
  957.  
  958. void COutliner::OnLButtonDblClk ( UINT nFlags, CPoint point )
  959. {
  960.     Default();
  961.     TipHide();
  962.  
  963.     int iRow, iCol;
  964.     
  965.     if (TestRowCol( point, iRow, iCol )) {
  966.         if ( m_pColumn[ iCol ]->iCommand == m_idImageCol ) {
  967.             void * pLineData;
  968.             if ( ( pLineData = AcquireLineData ( iRow ) ) ) {
  969.                 int iDepth;
  970.                 GetTreeInfo ( iRow, NULL, &iDepth, NULL );
  971.                 ReleaseLineData ( pLineData );
  972.  
  973.                 int iImageWidth = m_pIImage->GetImageWidth ( );
  974.                 RECT rcToggle = m_rcHit;
  975.                 rcToggle.left += iDepth * iImageWidth;
  976.                 rcToggle.right = rcToggle.left + iImageWidth;
  977.  
  978.                 if ( ::PtInRect( &rcToggle, point ) ) {
  979.                     DoToggleExpansion ( iRow );
  980.                     return;
  981.                 }
  982.             }
  983.         }
  984.         if ( ColumnCommand( m_pColumn[ iCol ]->iCommand, iRow ) )
  985.             return;
  986.  
  987.         SetCapture();
  988.         SelectItem( iRow, OUTLINER_LBUTTONDBLCLK, nFlags );
  989.     }
  990. }
  991.  
  992. int COutliner::GetTotalLines()
  993. {
  994.     return m_iTotalLines;
  995. }
  996.  
  997. int COutliner::GetDropLine()
  998. {
  999.     return m_iDragSelection;
  1000. }
  1001.  
  1002. int COutliner::GetDragHeartbeat()
  1003. {
  1004.     // Override to set a different drag time on scroll.
  1005.     return DRAG_HEARTBEAT;
  1006. }
  1007.  
  1008. HFONT COutliner::GetLineFont(void *pData)
  1009. {
  1010.     return m_hRegFont;
  1011. }
  1012.  
  1013. void COutliner::SetFocusLine( int iLine ) 
  1014. {
  1015.     if (iLine == -1)
  1016.         return;
  1017.     InvalidateLine(m_iFocus);
  1018.     m_iFocus = iLine;
  1019.     InvalidateLine(m_iFocus);
  1020. }
  1021.  
  1022. int COutliner::GetFocusLine()
  1023. {
  1024.     return m_iFocus;
  1025. }
  1026.  
  1027. int COutliner::GetDepth( int iLine )
  1028. {
  1029.     return 0;
  1030. }
  1031.  
  1032. int COutliner::GetNumChildren( int iLine )
  1033. {
  1034.     return 0;
  1035. }
  1036.  
  1037. int COutliner::GetParentIndex( int iLine )
  1038. {
  1039.     int depth = GetDepth( iLine );
  1040.     if ( iLine > 0 ) {
  1041.         int i = iLine - 1;
  1042.         while ( i > 0 && GetDepth( i ) >= depth ) {
  1043.             i--;
  1044.         }
  1045.         return i;
  1046.     } else {
  1047.         return 0;
  1048.     }
  1049. }
  1050.  
  1051. BOOL COutliner::IsCollapsed( int iLine )
  1052. {
  1053.     return FALSE;
  1054. }
  1055.  
  1056. void *COutliner::AcquireLineData( int iLine )
  1057. {
  1058.     return NULL;
  1059. }
  1060.  
  1061. void COutliner::ReleaseLineData( void *pData )
  1062. {
  1063.  
  1064. }
  1065.  
  1066. LPCTSTR COutliner::GetColumnText( UINT iCol, void *pData )
  1067. {
  1068.     return _T("");    
  1069. }
  1070.  
  1071. LPCTSTR COutliner::GetColumnTip( UINT iCol, void *pData )
  1072. {
  1073.     return NULL;    
  1074. }
  1075.  
  1076. BOOL COutliner::RenderData ( UINT idCol, CRect &rect, CDC &dc, LPCTSTR lpsz )
  1077. {
  1078.     return FALSE;
  1079. }
  1080.  
  1081. int COutliner::Expand(int iLine)
  1082. {
  1083.     return 0;
  1084. }
  1085.  
  1086. int COutliner::Collapse(int iLine)
  1087. {
  1088.     return 0;
  1089. }
  1090.  
  1091. int COutliner::ToggleExpansion(int iLine)
  1092. {
  1093.     return 0;
  1094. }
  1095.  
  1096. int COutliner::ExpandAll(int iLine)
  1097. {
  1098.     return DoExpandAll(iLine);
  1099. }
  1100.  
  1101. int COutliner::CollapseAll(int iLine)
  1102. {
  1103.     return DoCollapseAll(iLine);
  1104. }
  1105.  
  1106. void COutliner::GetTreeInfo( int iLine, unsigned long *pFlags, int *iDepth,
  1107.                              OutlinerAncestorInfo **pAncestor )
  1108. {
  1109.  
  1110. }
  1111.  
  1112. int COutliner::TranslateIcon( void *pData )
  1113. {
  1114.     return 0;
  1115. }
  1116.  
  1117. int COutliner::TranslateIconFolder( void *pData )
  1118. {
  1119.     return 0;
  1120. }
  1121.  
  1122. void COutliner::SelectItem( int iSel, int mode, UINT flags )
  1123. {
  1124.     void *pData;
  1125.     if ( pData = AcquireLineData( iSel ) ) {
  1126.         ReleaseLineData( pData );
  1127.         switch ( mode ) {
  1128.         case OUTLINER_LBUTTONDOWN:
  1129.             InvalidateLine( m_iSelection );
  1130.             m_iSelection = iSel;
  1131.             InvalidateLine( m_iSelection );
  1132.             break;
  1133.  
  1134.         case OUTLINER_LBUTTONUP:
  1135.             InvalidateLine( m_iFocus );
  1136.             m_iFocus = m_iSelection;
  1137.             InvalidateLine( m_iFocus );
  1138.             OnSelChanged();
  1139.             m_iLastSelected = m_iSelection;
  1140.             break;
  1141.  
  1142.         case 0:
  1143.             ASSERT(0);
  1144.  
  1145.         case OUTLINER_RBUTTONDOWN:
  1146.         case OUTLINER_KEYDOWN:
  1147.         case OUTLINER_SET:
  1148.             InvalidateLine( m_iFocus );
  1149.             InvalidateLine( m_iSelection );
  1150.             m_iFocus = m_iSelection = iSel;
  1151.             OnSelChanged();
  1152.             m_iLastSelected = m_iSelection;
  1153.             break;
  1154.  
  1155.         case OUTLINER_LBUTTONDBLCLK:
  1156.         case OUTLINER_RETURN:
  1157.             OnSelDblClk();
  1158.             break;
  1159.  
  1160.         default:
  1161.             ASSERT("What kind of garbage are you passing me?" == NULL);
  1162.         }
  1163.         UpdateWindow();
  1164.     }
  1165. }
  1166.  
  1167. void COutliner::InvalidateLine ( int iLineNo )
  1168. {
  1169.     if (iLineNo == -1)
  1170.         return;
  1171.     CRect rect, out;
  1172.     GetClientRect ( &rect );
  1173.     RectFromLine ( iLineNo - m_iTopLine, rect, out );
  1174.     InvalidateRect ( &out );
  1175. }
  1176.  
  1177. void COutliner::InvalidateLines( int iStart, int iCount )
  1178. {
  1179.     RECT rect, out;
  1180.  
  1181.     // Sanity check away
  1182.     int iInvStart = iStart - m_iTopLine;
  1183.     if (iInvStart < 0) {
  1184.         // Off top
  1185.         iCount += iInvStart; 
  1186.         iInvStart = 0;
  1187.     }
  1188.  
  1189.     if (iInvStart > m_iPaintLines)
  1190.          // Nothing visible changed
  1191.         return;
  1192.  
  1193.     int iInvCount = (iInvStart + iCount) > m_iPaintLines ? 
  1194.                     m_iPaintLines - iInvStart : iCount;
  1195.  
  1196.     if (iInvCount < 0)
  1197.         // Nothing visible changed
  1198.         return;
  1199.  
  1200.     // The case iInvCount < 0 is handled by for loop
  1201.  
  1202.     GetClientRect ( &rect );
  1203.     ::SetRect ( &out, 
  1204.                 rect.left, m_itemHeight * iInvStart, 
  1205.                 rect.right, m_itemHeight * (iInvStart + iInvCount) );
  1206.  
  1207.     InvalidateRect ( &out );
  1208. }
  1209.  
  1210. BOOL COutliner::HighlightIfDragging(void)
  1211. {
  1212.     return TRUE;
  1213. }
  1214.  
  1215. void COutliner::GetColumnRect( int iCol, RECT &rc )
  1216. {
  1217.     GetClientRect(&rc);
  1218.     rc.left = 0;
  1219.     rc.right = 0;
  1220.     if ( iCol >= 0 && iCol < m_iVisColumns ) {
  1221.         for (int i = 0; i <= iCol; i++) {
  1222.             rc.left = rc.right;
  1223.             rc.right += m_pColumn[ i ]->iCol;
  1224.         }
  1225.     }
  1226. }
  1227.  
  1228. void COutliner::InvalidateColumn( int iCol )
  1229. {
  1230.     RECT rc;
  1231.     GetColumnRect( iCol, rc );
  1232.     InvalidateRect( &rc );
  1233. }
  1234.  
  1235. void COutliner::OnTimer( UINT timer)
  1236. {
  1237.     if (timer == ID_OUTLINER_TIMER) {
  1238.         int flags = 0;
  1239.         if (GetKeyState(VK_SHIFT)&0x8000)
  1240.             flags |= MK_SHIFT;
  1241.         if (GetKeyState(VK_CONTROL)&0x8000)
  1242.             flags |= MK_CONTROL;
  1243.         SelectItem( m_iSelection,OUTLINER_TIMER, flags);
  1244.         KillTimer(ID_OUTLINER_TIMER);        
  1245.         return;
  1246.     }
  1247.     if (timer == ID_OUTLINER_HEARTBEAT) {
  1248.         POINT point;
  1249.         GetCursorPos(&point);
  1250.         ScreenToClient(&point);
  1251.  
  1252.         if (m_iTipState == TIP_WAITING) {
  1253.               CPoint ptCorner;
  1254.             int iRow, iCol;
  1255.  
  1256.             if (TestRowCol(point, iRow, iCol)) {
  1257.                  void * pLineData;
  1258.                 if ( pLineData = AcquireLineData ( m_iTipRow ) ) {
  1259.                     if ( ( iRow == m_iTipRow ) && ( iCol == m_iTipCol ) ) {
  1260.                         int x = 0;
  1261.                         if ( m_pColumn[ m_iTipCol ]->iCommand == m_idImageCol ) {
  1262.                              int iDepth = 0;
  1263.                              int iImageWidth = m_pIImage->GetImageWidth ( );
  1264.                              if ( m_bHasPipes ) {
  1265.                                  GetTreeInfo ( m_iTipRow, NULL, &iDepth, NULL );
  1266.                                  x += (iDepth + 1) * iImageWidth;
  1267.                              }
  1268.                              x += iImageWidth + OUTLINE_TEXT_OFFSET;
  1269.                         }
  1270.                         if ( m_pTip ) {
  1271.                             HFONT hTipFont = GetLineFont(pLineData);
  1272.                             LPCSTR lpszTipText = GetColumnTip(m_pColumn[ m_iTipCol ]->iCommand, pLineData);
  1273.                             DWORD dwStyle = IsSelected( iRow ) ? NSTTS_SELECTED : 0;
  1274.                             if (!lpszTipText) {
  1275.                                 lpszTipText = GetColumnText(m_pColumn[ m_iTipCol ]->iCommand, pLineData);
  1276.                             } else {
  1277.                                 dwStyle |= NSTTS_ALWAYSSHOW;
  1278.                             }
  1279.                             dwStyle |= m_pColumn[ m_iTipCol ]->alignment == AlignRight ? NSTTS_RIGHT : 0;
  1280.  
  1281.                             m_pTip->Show( this->GetSafeHwnd(),
  1282.                                           m_rcHit.left + x, m_rcHit.top, 
  1283.                                           m_pColumn[ m_iTipCol ]->iCol - x, m_itemHeight,
  1284.                                           lpszTipText,dwStyle, hTipFont);
  1285.                             m_iTipState = TIP_SHOWING;
  1286.                             if ( !(m_iTipTimer = SetTimer( ID_OUTLINER_HEARTBEAT, 100, NULL )) )
  1287.                                 // Can't get timer, so give up
  1288.                                 TipHide();
  1289.                         }
  1290.                     } else {
  1291.                         m_iTipTimer = SetTimer(ID_OUTLINER_HEARTBEAT, 100, NULL);
  1292.                     }
  1293.  
  1294.                     ReleaseLineData(pLineData);
  1295.                     return;
  1296.                 }
  1297.             }
  1298.              // For whatever reason we shouldn't show
  1299.             TipHide();
  1300.         } else { // Since we're not waiting we must be showing
  1301.             HandleMouseMove(point);            
  1302.         }
  1303.     }
  1304. }
  1305.  
  1306. void COutliner::PositionNext ( void )
  1307. {
  1308.     if ( m_iFocus < m_iTotalLines - 1 ) {
  1309.         m_iFocus++;
  1310.     } 
  1311. }
  1312.  
  1313. void COutliner::PositionPrevious ( void )
  1314. {
  1315.     if ( m_iFocus > 0 ) {
  1316.         m_iFocus--;
  1317.     }
  1318. }
  1319.  
  1320. void COutliner::PositionHome ( void )
  1321. {
  1322.     m_iFocus = 0;
  1323.     m_iTopLine = 0;
  1324. }
  1325.  
  1326. void COutliner::PositionEnd ( void )
  1327. {
  1328.     m_iFocus = m_iTotalLines - 1;
  1329.     if (m_iFocus > ( m_iTopLine + m_iPaintLines - 2 ) ) {
  1330.         m_iTopLine = m_iFocus - (m_iPaintLines - 2);
  1331.     }
  1332. }
  1333.  
  1334. void COutliner::PositionPageDown()
  1335. {
  1336.     if ( ( m_iFocus + m_iPaintLines ) > m_iTotalLines ) {
  1337.         m_iFocus = m_iTotalLines - 1;
  1338.     } else {
  1339.         m_iFocus += m_iPaintLines - 2;
  1340.     }
  1341. }
  1342.  
  1343. void COutliner::PositionPageUp()
  1344. {
  1345.     if ( ( m_iFocus - m_iPaintLines - 2) < 0 ){
  1346.         m_iFocus = 0;
  1347.     } else {
  1348.         m_iFocus -= m_iPaintLines - 2;
  1349.     }
  1350. }
  1351.  
  1352. void COutliner::OnSysKeyDown( UINT nChar, UINT nRepCnt, UINT nFlags )
  1353. {
  1354.     TipHide();
  1355.     switch (nChar) {
  1356.     case VK_RETURN:
  1357.         if (m_iFocus >= 0)
  1358.             SelectItem(m_iFocus,OUTLINER_PROPERTIES);
  1359.         break;
  1360.     }
  1361.     CWnd::OnSysKeyDown(nChar,nRepCnt,nFlags);
  1362. }
  1363.  
  1364. void COutliner::OnKeyUp ( UINT nChar, UINT nRepCnt, UINT nFlags )
  1365. {
  1366.     Default();
  1367.     if (m_iSelection != m_iLastSelected)
  1368.         SetTimer(ID_OUTLINER_TIMER,ID_OUTLINER_TIMER_DELAY,NULL);
  1369. }
  1370.  
  1371. void COutliner::OnKeyDown ( UINT nChar, UINT nRepCnt, UINT nFlags )
  1372. {
  1373.     int iOldSel = m_iSelection;
  1374.     int iOldTopLine = m_iTopLine;
  1375.  
  1376.     TipHide();
  1377.  
  1378.     if ( (GetKeyState(VK_CONTROL)&0x8000) && (nChar != VK_DELETE) ) {
  1379.         int nSBCode = -1;
  1380.         switch (nChar) {
  1381.             case VK_DOWN:
  1382.                 nSBCode = SB_LINEDOWN;
  1383.                 break;
  1384.  
  1385.             case VK_UP:
  1386.                 nSBCode = SB_LINEUP;
  1387.                 break;
  1388.  
  1389.             case VK_NEXT:
  1390.                 nSBCode = SB_PAGEDOWN;
  1391.                 break;                
  1392.  
  1393.             case VK_PRIOR:
  1394.                 nSBCode = SB_PAGEUP;
  1395.                 break;
  1396.  
  1397.             case VK_HOME:
  1398.                 nSBCode = SB_TOP;
  1399.                 break;
  1400.  
  1401.             case VK_END:
  1402.                 nSBCode = SB_BOTTOM;
  1403.                 break;
  1404.  
  1405.             default:
  1406.                 Default();
  1407.         }
  1408.         if ( nSBCode != -1 ) {
  1409.             OnVScroll( nSBCode, 0, GetScrollBarCtrl( SB_VERT ));
  1410.         }
  1411.         return;
  1412.     } else {
  1413.         switch (nChar) {
  1414.             case VK_DELETE:
  1415.                 DeleteItem ( m_iSelection );
  1416.                 break;
  1417.  
  1418.             case VK_DOWN:
  1419.                 PositionNext();
  1420.                 break;
  1421.  
  1422.             case VK_UP:
  1423.                 PositionPrevious();
  1424.                 break;
  1425.  
  1426.             case VK_LEFT:
  1427.                 if ( GetNumChildren( m_iSelection ) > 0 && !IsCollapsed( m_iSelection ) ) {
  1428.                     DoCollapse( m_iSelection );
  1429.                     iOldTopLine = m_iTopLine; // Scroll is handled by DoCollapse
  1430.                 } else {
  1431.                     int idx = GetParentIndex( m_iSelection );
  1432.                     SelectItem( idx );
  1433.                     ScrollIntoView( idx );
  1434.                 }
  1435.                 break;
  1436.  
  1437.             case VK_RIGHT:
  1438.                 if ( GetNumChildren( m_iSelection ) > 0 ) {
  1439.                     if ( IsCollapsed( m_iSelection ) ) {
  1440.                         DoExpand( m_iSelection );
  1441.                         iOldTopLine = m_iTopLine; // Scroll is handled by DoExpand
  1442.                     } else {
  1443.                         PositionNext();
  1444.                     }
  1445.                 }
  1446.                 break;
  1447.             case VK_NEXT:
  1448.                 PositionPageDown();
  1449.                 break;                
  1450.  
  1451.             case VK_PRIOR:
  1452.                 PositionPageUp();
  1453.                 break; 
  1454.             
  1455.             case VK_MENU:               
  1456.                 if (GetAsyncKeyState(VK_RETURN)&0x80)
  1457.                     SelectItem( m_iSelection,OUTLINER_PROPERTIES);
  1458.                 break;
  1459.             case VK_RETURN:
  1460.                 SelectItem ( m_iFocus, OUTLINER_RETURN );
  1461.                 break;
  1462.  
  1463.             case VK_HOME:
  1464.                 PositionHome ( );
  1465.                 break;
  1466.  
  1467.             case VK_END:
  1468.                 PositionEnd ( );
  1469.                 break;
  1470.  
  1471.             case VK_SUBTRACT:
  1472.                 if( m_iSelection >= 0 ) {
  1473.                     DoCollapse( m_iSelection );
  1474.                     iOldTopLine = m_iTopLine; // Scroll is handled by DoCollapse
  1475.                 }
  1476.                 break;
  1477.  
  1478.             case VK_ADD:
  1479.                 if( m_iSelection >= 0 ) {
  1480.                     DoExpand( m_iSelection );
  1481.                     iOldTopLine = m_iTopLine; // Scroll is handled by DoExpand
  1482.                 }
  1483.                 break;
  1484.  
  1485.             case VK_SPACE:
  1486.                 if( m_iSelection >= 0 ) {
  1487.                     DoToggleExpansion ( m_iSelection );
  1488.                     iOldTopLine = m_iTopLine; // Scroll is handled by DoToggleExpansion
  1489.                 }
  1490.                 break;
  1491.       
  1492.             case VK_MULTIPLY:
  1493.                 if ( m_iSelection >= 0) {
  1494.                     ExpandAll( m_iSelection );
  1495.                     iOldTopLine = m_iTopLine; // Scroll is handled by ExpandAll
  1496.                 }
  1497.                 break;
  1498.  
  1499.             case VK_DIVIDE:
  1500.                 if ( m_iSelection >= 0) {
  1501.                     CollapseAll( m_iSelection );
  1502.                     iOldTopLine = m_iTopLine; // Scroll is handled by CollapseAll
  1503.                 }
  1504.                 break;
  1505.  
  1506.             default:
  1507.                 Default();
  1508.                 return;
  1509.         }
  1510.     }
  1511.  
  1512.     m_iSelection = m_iFocus;
  1513.  
  1514.     SetScrollPos ( SB_VERT, m_iTopLine );
  1515.  
  1516.      if ( m_iSelection < m_iTopLine && m_iSelection >= 0) {
  1517.         m_iTopLine = m_iSelection;
  1518.     }
  1519.     if ( m_iSelection > ( m_iTopLine + m_iPaintLines - 2 ) ) {
  1520.         m_iTopLine = m_iSelection - (m_iPaintLines - 2);
  1521.     }
  1522.  
  1523.     BOOL bRepaint = FALSE;
  1524.  
  1525.     int iDiff = iOldTopLine - m_iTopLine;
  1526.     if ( iDiff != 0 )
  1527.     {
  1528.         ScrollWindow ( 0, m_itemHeight * iDiff );
  1529.         bRepaint = TRUE;
  1530.     }
  1531.  
  1532.     if ( m_iSelection != iOldSel )
  1533.     {
  1534.         InvalidateLine(m_iSelection);
  1535.         InvalidateLine(iOldSel);
  1536.         UINT flags = 0;
  1537.         if (GetKeyState(VK_SHIFT)&0x8000)
  1538.             flags |= MK_SHIFT;
  1539.         if( m_iSelection >= 0 )
  1540.             SelectItem ( m_iSelection, OUTLINER_KEYDOWN, flags );
  1541.         KillTimer(ID_OUTLINER_TIMER);
  1542.  
  1543.         bRepaint = TRUE;
  1544.     }
  1545.  
  1546.     if (bRepaint)
  1547.         UpdateWindow ( );
  1548.  
  1549.     Default();
  1550. }
  1551.  
  1552. void COutliner::OnSysColorChange ( )
  1553. {
  1554.  
  1555.     CWnd::OnSysColorChange ( );
  1556.     m_pIImage->ReInitialize();
  1557.     m_pIUserImage->ReInitialize();
  1558.     Invalidate ( );
  1559. }
  1560.  
  1561. UINT COutliner::OnGetDlgCode( )
  1562. {
  1563.     return DLGC_WANTARROWS;
  1564. }
  1565.  
  1566. void COutliner::OnKillFocus ( CWnd * pNewWnd )
  1567. {
  1568.     CWnd::OnKillFocus ( pNewWnd );
  1569.     if (m_iSelection >= 0)
  1570.         for (int i =0; i < (m_iTopLine+m_iPaintLines); i++)
  1571.             if (IsSelected(i))
  1572.                 InvalidateLine(i);
  1573.  
  1574.     ((COutlinerParent*)GetParent())->UpdateFocusFrame();
  1575. }
  1576.  
  1577. void COutliner::OnSetFocus ( CWnd * pOldWnd )
  1578. {
  1579.     Default();
  1580.  
  1581.     if (m_iSelection >= 0)
  1582.         for (int i =0; i < (m_iTopLine+m_iPaintLines); i++)
  1583.             if (IsSelected(i))
  1584.                 InvalidateLine(i);
  1585.  
  1586.     ((COutlinerParent*)GetParent())->UpdateFocusFrame();
  1587. }
  1588.  
  1589. void COutliner::SetTotalLines( int iLines )
  1590. {
  1591.     m_iTotalLines = iLines;
  1592.     if (m_iTopLine > m_iTotalLines) {
  1593.         m_iTopLine = m_iTotalLines;
  1594.     }
  1595.     EnableScrollBars();
  1596. }
  1597.  
  1598. void COutliner::EnableScrollBars ( void )
  1599. {
  1600.     if (m_iTotalLines >= m_iPaintLines) {
  1601.         ShowScrollBar(SB_VERT);
  1602. #ifdef WIN32
  1603.         SCROLLINFO ScrollInfo;
  1604.         ScrollInfo.cbSize = sizeof(SCROLLINFO);
  1605.         ScrollInfo.fMask = SIF_PAGE|SIF_RANGE|SIF_POS;
  1606.         ScrollInfo.nMin = 0;
  1607.         ScrollInfo.nMax = m_iTotalLines - 1;
  1608.         ScrollInfo.nPage = m_iPaintLines - 1;
  1609.         ScrollInfo.nPos = m_iTopLine;
  1610.         SetScrollInfo(SB_VERT,&ScrollInfo, TRUE);
  1611. #else
  1612.         SetScrollPos( SB_VERT, m_iTopLine );
  1613.         SetScrollRange(SB_VERT,0,(m_iTotalLines - m_iPaintLines)+1, TRUE);
  1614. #endif
  1615.     } else {
  1616.         if (m_iTopLine > 0) {
  1617.             m_iTopLine = 0;
  1618.             Invalidate();
  1619.         }
  1620.         ShowScrollBar ( SB_VERT, FALSE );
  1621.     }
  1622. }
  1623.  
  1624. void COutliner::ScrollIntoView( int iVisible )
  1625. {
  1626.     if (iVisible != -1) {
  1627.          int iOldTop = m_iTopLine;
  1628.         CRect rect;
  1629.         GetClientRect(&rect);
  1630.         int iAdjust = ((rect.Height() - ((m_iPaintLines-1)*m_itemHeight))+2)/m_itemHeight;
  1631.         if (iAdjust == 0) 
  1632.             iAdjust = 1;
  1633.         else
  1634.             iAdjust = 0;
  1635.  
  1636.         if ( ( iVisible < m_iTopLine ) ||
  1637.             ( iVisible > ((m_iTopLine + m_iPaintLines) - iAdjust))) {
  1638.  
  1639.             m_iTopLine = iVisible - (m_iPaintLines/2);
  1640.             if ( m_iTopLine < 0 )
  1641.                 m_iTopLine = 0;
  1642.             Invalidate ( );
  1643.         }
  1644.         else if (iVisible == ((m_iTopLine+m_iPaintLines)-iAdjust)) {
  1645.             m_iTopLine++;
  1646.             Invalidate();
  1647.         }
  1648.         UpdateWindow( );
  1649.         SetScrollPos( SB_VERT, m_iTopLine );
  1650.     }
  1651. }
  1652.  
  1653. void COutliner::EnsureVisible( int iVisible )
  1654. {
  1655.     if (iVisible != -1) {
  1656.         int iOldTop = m_iTopLine;
  1657.         if (iVisible < m_iTopLine) {
  1658.             m_iTopLine = iVisible;
  1659.         } else if (iVisible >= (m_iTopLine + m_iPaintLines - 1)) {
  1660.             m_iTopLine = iVisible - m_iPaintLines + 2;
  1661.         } else {
  1662.             return;
  1663.         }
  1664.         int iDelta = iOldTop - m_iTopLine;
  1665.  
  1666.         ScrollWindow( 0, m_itemHeight * iDelta );
  1667.         UpdateWindow( );
  1668.         SetScrollPos( SB_VERT, m_iTopLine );
  1669.     }
  1670. }
  1671.  
  1672. void COutliner::OnVScroll( UINT nSBCode, UINT nPos, CScrollBar* pScrollBar )
  1673. {
  1674.     int iOldTopLine = m_iTopLine;
  1675.     switch ( nSBCode )
  1676.     {
  1677.         case SB_BOTTOM:
  1678.             m_iTopLine = m_iTotalLines - (m_iPaintLines - 2);
  1679.             break;
  1680.         case SB_LINEDOWN:
  1681.             if ( m_iTopLine + ( m_iPaintLines - 1 ) < m_iTotalLines + 1 )
  1682.                 m_iTopLine++;
  1683.             break;
  1684.         case SB_LINEUP:
  1685.             if ( m_iTopLine )
  1686.                 m_iTopLine--;
  1687.             break;
  1688.         case SB_PAGEDOWN:
  1689.             if ( m_iTopLine + ( m_iPaintLines - 1 ) < m_iTotalLines )
  1690.                 m_iTopLine += ( m_iPaintLines - 1 );
  1691.             break;
  1692.         case SB_PAGEUP:
  1693.             m_iTopLine -= (m_iPaintLines - 1);
  1694.             break;
  1695.         case SB_THUMBPOSITION:
  1696.             m_iTopLine = nPos;
  1697.             break;
  1698.         case SB_THUMBTRACK:
  1699.             m_iTopLine = nPos;
  1700.             break;
  1701.         case SB_TOP:
  1702.             m_iTopLine = 0;
  1703.             break;
  1704.     }
  1705.  
  1706.     if ( m_iTopLine < 0 )
  1707.         m_iTopLine = 0;
  1708.  
  1709.     int iDiff = iOldTopLine - m_iTopLine;
  1710.     if ( iDiff != 0 )
  1711.     {
  1712.         ScrollWindow ( 0, m_itemHeight * iDiff );
  1713.         UpdateWindow ( );
  1714.     }
  1715.  
  1716.     SetScrollPos ( SB_VERT, m_iTopLine );
  1717.     Default();
  1718. }
  1719.  
  1720. BOOL COutliner::ViewerHasFocus ( )
  1721. {
  1722.     return ( GetFocus ( ) == this );
  1723. }
  1724.  
  1725. void COutliner::DoToggleExpansion( int iLine )
  1726. {
  1727.     int iDelta = ToggleExpansion( iLine );
  1728.     if ( iDelta > 0 ) {
  1729.         iDelta = iDelta > m_iPaintLines - 2 ? m_iPaintLines - 2 : iDelta;
  1730.         EnsureVisible( iLine + iDelta );
  1731.     }
  1732. }
  1733.  
  1734.  
  1735. void COutliner::DoExpand( int iLine )
  1736. {
  1737.     int iDelta = Expand( iLine );
  1738.     if ( iDelta > 0 ) {
  1739.         iDelta = iDelta > m_iPaintLines - 2 ? m_iPaintLines - 2 : iDelta;
  1740.         EnsureVisible( iLine + iDelta );
  1741.     }
  1742. }
  1743.  
  1744. void COutliner::DoCollapse( int iLine )
  1745. {
  1746.     Collapse( iLine );
  1747. }
  1748.  
  1749. int COutliner::DoExpandAll( int iLine )
  1750. {
  1751.     int iDelta = 0;
  1752.     int iDepth = GetDepth( iLine );
  1753.     iDelta += Expand(iLine);
  1754.     
  1755.     for (int i = iLine + 1; GetDepth(i) > iDepth; i++)
  1756.         iDelta += Expand(i);    
  1757.  
  1758.     if ( iDelta > 0 ) {
  1759.         iDelta = iDelta > m_iPaintLines - 2 ? m_iPaintLines - 2 : iDelta;
  1760.         EnsureVisible( iLine + iDelta );
  1761.     }
  1762.     return iDelta;
  1763. }
  1764.  
  1765. int COutliner::DoCollapseAll( int iLine )
  1766. {
  1767.     int iDelta = 0;
  1768.     int iDepth = GetDepth( iLine );
  1769.     int i = iLine;
  1770.     while ((i + 1) < m_iTotalLines && GetDepth(i + 1) > iDepth)
  1771.         i++;
  1772.  
  1773.     while (i >= iLine) {
  1774.         iDelta += Collapse(i);
  1775.         i--;
  1776.     }
  1777.     return iDelta;
  1778. }
  1779.  
  1780. int COutliner::GetPipeIndex (void *pData, int iDepth, OutlinerAncestorInfo * pAncestor )
  1781. {
  1782.     int iTranslated = TranslateIconFolder(pData);
  1783.     switch ( iTranslated )
  1784.     {
  1785.         case OUTLINER_OPENFOLDER:
  1786.         case OUTLINER_CLOSEDFOLDER:
  1787.  
  1788.             if ( iTranslated == OUTLINER_OPENFOLDER )
  1789.             {
  1790.                 if ( pAncestor->has_prev && pAncestor->has_next )
  1791.                     return IDX_OPENMIDDLEPARENT;
  1792.                 else if ( pAncestor->has_prev )
  1793.                     return IDX_OPENBOTTOMPARENT;
  1794.                 else if ( pAncestor->has_next &&  iDepth )
  1795.                     return IDX_OPENMIDDLEPARENT;
  1796.                 else if ( pAncestor->has_next )         
  1797.                     return IDX_OPENTOPPARENT;
  1798.                 else if ( iDepth )
  1799.                     return IDX_OPENBOTTOMPARENT;
  1800.                 else
  1801.                     return IDX_OPENSINGLEPARENT;
  1802.             }
  1803.             else
  1804.             {
  1805.                 if ( pAncestor->has_prev && pAncestor->has_next )
  1806.                     return IDX_CLOSEDMIDDLEPARENT;
  1807.                 else if ( pAncestor->has_prev )
  1808.                     return IDX_CLOSEDBOTTOMPARENT;
  1809.                 else if (  pAncestor->has_next && iDepth )
  1810.                     return IDX_CLOSEDMIDDLEPARENT;
  1811.                 else if ( pAncestor->has_next )         
  1812.                     return IDX_CLOSEDTOPPARENT;
  1813.                 else if ( iDepth )
  1814.                     return IDX_CLOSEDBOTTOMPARENT;
  1815.                 else
  1816.                     return IDX_CLOSEDSINGLEPARENT;
  1817.             }
  1818.             break;
  1819.  
  1820.         default:
  1821.  
  1822.             if ( pAncestor->has_prev && pAncestor->has_next )
  1823.                 return IDX_MIDDLEITEM;
  1824.             else if ( pAncestor->has_prev )
  1825.                 return IDX_BOTTOMITEM;
  1826.             else if ( pAncestor->has_next && iDepth )
  1827.                 return IDX_MIDDLEITEM;
  1828.             else if ( pAncestor->has_next )         
  1829.                 return IDX_TOPITEM;
  1830.             else if ( iDepth )
  1831.                 return IDX_BOTTOMITEM;
  1832.             break;
  1833.             
  1834.     }
  1835.     return IDX_EMPTYITEM;
  1836. }
  1837.  
  1838. void COutliner::RectFromLine ( int iLineNo, LPRECT lpRect, LPRECT lpOutRect )
  1839. {
  1840.     ::SetRect ( lpOutRect, 
  1841.                 0, m_itemHeight * iLineNo, 
  1842.                 lpRect->right, m_itemHeight * iLineNo + m_itemHeight );
  1843. }
  1844.  
  1845. void COutliner::EraseLine ( int iLineNo, HDC hdc, LPRECT lpWinRect )
  1846. {
  1847.     if ( iLineNo >= 0 ) {
  1848.         RECT rect;
  1849.         RectFromLine ( iLineNo, lpWinRect, &rect );  
  1850.         ::FillRect(hdc, &rect, (HBRUSH) GetCurrentObject(hdc, OBJ_BRUSH));
  1851.     }
  1852. }
  1853.  
  1854.  
  1855. int COutliner::DrawPipes ( int iLineNo, int iColNo, int offset, HDC hdc, void * pLineData )
  1856. {
  1857.     int iImageWidth = m_pIImage->GetImageWidth ( );
  1858.     int iMaxX = offset + m_pColumn[ iColNo ]->iCol;
  1859.     int idx;
  1860.  
  1861.     int iDepth;
  1862.     uint32 flags;
  1863.     OutlinerAncestorInfo * pAncestor;
  1864.     GetTreeInfo ( m_iTopLine + iLineNo, &flags, &iDepth, &pAncestor );
  1865.  
  1866.     RECT rect;
  1867.     rect.left = offset;
  1868.     rect.right = rect.left + iImageWidth;
  1869.     rect.top = iLineNo * m_itemHeight;
  1870.     rect.bottom = rect.top + m_itemHeight;
  1871.  
  1872.     if ( m_bHasPipes ) {
  1873.         for ( int i = 0; i < iDepth; i++ ) {
  1874.             if ( rect.right <= iMaxX ) {
  1875.                 if ( pAncestor && pAncestor[ i ].has_next ) {
  1876.                     m_pIImage->DrawImage( IDX_VERTPIPE, rect.left, rect.top, hdc, FALSE );
  1877.                 } else {
  1878.                     ::FillRect(hdc, &rect, (HBRUSH) GetCurrentObject(hdc, OBJ_BRUSH));
  1879.                 }
  1880.             }
  1881.             rect.left += iImageWidth;
  1882.             rect.right += iImageWidth;
  1883.         }
  1884.     
  1885.         if ( rect.right <= iMaxX ) {
  1886.             idx = 0;
  1887.             if ( pAncestor ) {
  1888.                 idx = GetPipeIndex ( pLineData, iDepth, &pAncestor[iDepth] );
  1889.             }
  1890.             if ( idx ) { 
  1891.                 m_pIImage->DrawImage( idx, rect.left, rect.top, hdc, FALSE );
  1892.             } else {
  1893.                 ::FillRect(hdc, &rect, (HBRUSH) GetCurrentObject(hdc, OBJ_BRUSH));
  1894.             }
  1895.         }
  1896.         rect.left += iImageWidth;
  1897.         rect.right += iImageWidth;
  1898.     }
  1899.     if ( rect.right <= iMaxX ) {
  1900.         idx = TranslateIcon (pLineData);
  1901.         m_pIUserImage->DrawImage ( idx, rect.left, rect.top, hdc, FALSE );
  1902.     }
  1903.     return rect.right;
  1904. }
  1905.  
  1906. void COutliner::DrawColumnText ( HDC hdc, LPRECT lpColumnRect, LPCTSTR lpszString,
  1907.                                  CropType_t cropping, AlignType_t alignment )
  1908. {
  1909.     if (!(lpColumnRect->right - lpColumnRect->left))
  1910.         return;
  1911.     ASSERT(lpszString);
  1912.     int iLength = _tcslen(lpszString);
  1913.     if (!iLength)
  1914.         return;
  1915.  
  1916.     UINT dwDTFormat = DT_NOCLIP | DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER;
  1917.     switch (alignment) {
  1918.     case AlignCenter:
  1919.         dwDTFormat |= DT_CENTER;
  1920.         break;
  1921.     case AlignRight:
  1922.         dwDTFormat |= DT_RIGHT;
  1923.         break;
  1924.     case AlignLeft:
  1925.     default:
  1926.         dwDTFormat |= DT_LEFT;
  1927.     }
  1928.  
  1929.     UINT dwMoreFormat = 0;
  1930.     switch (cropping) {
  1931.     case CropCenter:
  1932.         dwMoreFormat |= WFE_DT_CROPCENTER;
  1933.         break;
  1934.     case CropLeft:
  1935.         dwMoreFormat |= WFE_DT_CROPLEFT;
  1936.         break;
  1937.     case CropRight:
  1938.     default:
  1939.         dwMoreFormat |= WFE_DT_CROPRIGHT;
  1940.         break;
  1941.     }
  1942.  
  1943.     RECT textRect = *lpColumnRect;
  1944.     // Adjust the text rectangle for the left and right margins
  1945.     textRect.left += COL_LEFT_MARGIN;
  1946.     textRect.right -= COL_LEFT_MARGIN;
  1947.  
  1948.     WFE_DrawTextEx( m_iCSID, hdc, (LPTSTR) lpszString, iLength, &textRect, dwDTFormat, dwMoreFormat );
  1949. }
  1950.  
  1951. void COutliner::PaintColumn ( int iLineNo, int iColumn, LPRECT lpColumnRect, 
  1952.                               HDC hdc, void * pLineData )
  1953. {
  1954.     if (iColumn < m_iVisColumns) {
  1955.         LPCTSTR lpsz = GetColumnText (m_pColumn[ iColumn ]->iCommand,pLineData);
  1956.         if ( !RenderData( m_pColumn[iColumn]->iCommand, CRect(lpColumnRect), 
  1957.                           *CDC::FromHandle( hdc ), lpsz) ) {
  1958.             if (lpsz) {
  1959.                 DrawColumnText ( hdc, lpColumnRect, lpsz, 
  1960.                                  m_pColumn[ iColumn ]->cropping, 
  1961.                                  m_pColumn[ iColumn ]->alignment );
  1962.             }
  1963.         }
  1964.     }
  1965. }
  1966.  
  1967. void COutliner::PaintLine ( int iLineNo, HDC hdc, LPRECT lpPaintRect )
  1968. {
  1969.     void * pLineData;
  1970.     int iImageWidth = m_pIImage->GetImageWidth ( );
  1971.     CRect WinRect;
  1972.     GetClientRect(&WinRect);
  1973.  
  1974.     int y = m_itemHeight * iLineNo;
  1975.  
  1976.     int iColumn, offset;
  1977.     CRect rectColumn, rectInter;
  1978.  
  1979.     rectColumn.top = y;
  1980.     rectColumn.bottom = y + m_itemHeight;
  1981.  
  1982.     if ( !( pLineData = AcquireLineData( iLineNo + m_iTopLine )) ) {
  1983.         EraseLine ( iLineNo, hdc, lpPaintRect );
  1984.         if (ViewerHasFocus() && HasFocus(iLineNo + m_iTopLine)) {
  1985.             rectColumn.left = WinRect.left;
  1986.             rectColumn.right = WinRect.right;
  1987.             DrawFocusRect ( hdc, &rectColumn );
  1988.         }
  1989.         return;
  1990.     }
  1991.  
  1992.     HFONT hOldFont =(HFONT) ::SelectObject ( hdc, GetLineFont ( pLineData ) );
  1993.  
  1994.     for ( iColumn = offset = 0; iColumn < m_iVisColumns; iColumn++ )
  1995.     {
  1996.         rectColumn.left = offset;
  1997.         rectColumn.right = offset + m_pColumn[ iColumn ]->iCol;
  1998.  
  1999.         if ( rectInter.IntersectRect ( &rectColumn, lpPaintRect ) ) {
  2000.             ::FillRect(hdc, &rectColumn, (HBRUSH) GetCurrentObject(hdc, OBJ_BRUSH));
  2001.             if ( m_pColumn[ iColumn ]->iCommand == m_idImageCol ) {
  2002.                 rectColumn.left = DrawPipes ( iLineNo, iColumn, offset, hdc, pLineData );
  2003.                 rectColumn.left += OUTLINE_TEXT_OFFSET;
  2004.             }
  2005.             PaintColumn ( iLineNo, iColumn, rectColumn, hdc, pLineData );
  2006.         }
  2007.  
  2008.         offset += m_pColumn[ iColumn ]->iCol;
  2009.     }
  2010.  
  2011.     rectColumn.left = offset;
  2012.     rectColumn.right = WinRect.right;
  2013.  
  2014.     ::FillRect(hdc, &rectColumn, (HBRUSH) GetCurrentObject(hdc, OBJ_BRUSH));
  2015.     PaintColumn ( iLineNo, iColumn, rectColumn, hdc, pLineData );
  2016.  
  2017.     rectColumn.left = WinRect.left;
  2018.     rectColumn.right = WinRect.right;
  2019.  
  2020.     // if we are dragging we and we don't highlight we need to draw the drag line
  2021.     if(m_iDragSelection == m_iTopLine + iLineNo && !HighlightIfDragging())
  2022.         PaintDragLine(hdc, rectColumn);
  2023.  
  2024.     if (ViewerHasFocus() && HasFocus(iLineNo + m_iTopLine)){
  2025.         DrawFocusRect ( hdc, &rectColumn );
  2026.     }
  2027.  
  2028.     ::SelectObject ( hdc, hOldFont );
  2029.     ReleaseLineData ( pLineData );
  2030. }
  2031.  
  2032. void COutliner::PaintDragLine(HDC hdc, CRect &rectColumn)
  2033. {
  2034.  
  2035. }
  2036.  
  2037. BOOL COutliner::IsSelected ( int iLineNo )
  2038. {
  2039.     return ( iLineNo == m_iSelection );
  2040. }
  2041.  
  2042. BOOL COutliner::HasFocus ( int iLineNo )
  2043. {
  2044.     return ( iLineNo == m_iFocus );
  2045. }
  2046.  
  2047. BOOL COutliner::OnSetCursor( CWnd* pWnd, UINT nHitTest, UINT message )
  2048. {
  2049.     if (!CWnd::OnSetCursor( pWnd, nHitTest, message )) {
  2050.         SetCursor ( ::LoadCursor( NULL, IDC_ARROW ) );
  2051.     }
  2052.     return TRUE;    
  2053. }
  2054.  
  2055. void COutliner::OnPaint ( )
  2056. {
  2057.     RECT rcClient;
  2058.     GetClientRect(&rcClient);
  2059.     CPaintDC pdc ( this );
  2060.  
  2061.     HBRUSH hRegBrush = ::CreateSolidBrush( GetSysColor( COLOR_WINDOW ) );
  2062.     HPEN hRegPen = ::CreatePen( PS_SOLID, 0, GetSysColor ( COLOR_WINDOW ) );
  2063.     HBRUSH hHighBrush = ::CreateSolidBrush( GetSysColor( COLOR_HIGHLIGHT ) );
  2064.     HPEN hHighPen = ::CreatePen( PS_SOLID, 0, GetSysColor ( COLOR_HIGHLIGHT ) );
  2065.  
  2066.     HBRUSH hOldBrush = (HBRUSH) pdc.SelectObject ( hRegBrush );
  2067.     HPEN hOldPen = (HPEN) pdc.SelectObject ( hRegPen );
  2068.     COLORREF cOldText = pdc.SetTextColor ( GetSysColor ( COLOR_WINDOWTEXT ) );
  2069.     COLORREF cOldBk = pdc.SetBkColor ( GetSysColor ( COLOR_WINDOW ) );
  2070.  
  2071.     int i;            
  2072.     for ( i = pdc.m_ps.rcPaint.top / m_itemHeight; 
  2073.         i < ( pdc.m_ps.rcPaint.bottom / m_itemHeight ) + 1; i++ ) {
  2074.             int index = m_iTopLine + i;
  2075.  
  2076.             if ( ( IsSelected( index ) && ViewerHasFocus () && m_iDragSelection == -1 ) ||
  2077.                  (( index == m_iDragSelection ) && HighlightIfDragging()) ) {
  2078.                 pdc.SelectObject ( hHighBrush );
  2079.                 pdc.SelectObject ( hHighPen );
  2080.                 pdc.SetTextColor ( GetSysColor ( COLOR_HIGHLIGHTTEXT ) );
  2081.                 pdc.SetBkColor ( GetSysColor ( COLOR_HIGHLIGHT ) );
  2082.                 m_pIImage->UseHighlight ( );
  2083.                 m_pIUserImage->UseHighlight( );
  2084.  
  2085.                 PaintLine ( i, pdc.m_hDC, &pdc.m_ps.rcPaint );
  2086.  
  2087.                 pdc.SetTextColor ( GetSysColor ( COLOR_WINDOWTEXT ) );
  2088.                 pdc.SetBkColor ( GetSysColor ( COLOR_WINDOW ) );
  2089.                 pdc.SelectObject ( hRegBrush);
  2090.                 pdc.SelectObject ( hRegPen );
  2091.                 m_pIImage->UseNormal( );
  2092.                 m_pIUserImage->UseNormal( );
  2093.             }
  2094.             else    
  2095.                 PaintLine ( i, pdc.m_hDC, &pdc.m_ps.rcPaint );
  2096.  
  2097.              if ( !ViewerHasFocus() && IsSelected( m_iTopLine + i ) ) {
  2098.                 RECT rcLine;
  2099.                 RectFromLine( i, &rcClient, &rcLine);
  2100.                 DrawFocusRect ( pdc.m_hDC, &rcLine );
  2101.             }
  2102.        }
  2103.  
  2104.     pdc.SetTextColor ( cOldText );
  2105.     pdc.SetBkColor ( cOldBk );        
  2106.     pdc.SelectObject ( hOldPen );
  2107.     pdc.SelectObject ( hOldBrush );
  2108.  
  2109.     VERIFY(DeleteObject( hRegBrush ));
  2110.     VERIFY(DeleteObject( hRegPen ));
  2111.     VERIFY(DeleteObject( hHighBrush ));
  2112.     VERIFY(DeleteObject( hHighPen ));
  2113. }
  2114.  
  2115. int COutliner::OnCreate ( LPCREATESTRUCT lpCreateStruct )
  2116. {
  2117.     int iRetVal = CWnd::OnCreate ( lpCreateStruct );
  2118.     
  2119.     m_pDropTarget = CreateDropTarget();
  2120.     
  2121.     m_pDropTarget->Register(this);
  2122.     InitializeClipFormats ( );
  2123.  
  2124.     SetCSID(INTL_DefaultWinCharSetID(0)); 
  2125.  
  2126.     return iRetVal;
  2127. }
  2128.  
  2129. COutlinerDropTarget* COutliner::CreateDropTarget()
  2130. {
  2131.     return new COutlinerDropTarget(this);
  2132. }
  2133.  
  2134. void COutliner::SetCSID(int csid)
  2135. {
  2136.     CClientDC pdc ( this );
  2137.     LOGFONT lf;
  2138.  
  2139.     m_iCSID = csid;
  2140.  
  2141.     if (m_hRegFont) {
  2142.         theApp.ReleaseAppFont(m_hRegFont);
  2143.     }
  2144.     if (m_hBoldFont) {
  2145.         theApp.ReleaseAppFont(m_hBoldFont);
  2146.     }
  2147.     if (m_hItalFont) {
  2148.         theApp.ReleaseAppFont(m_hItalFont);
  2149.     }
  2150.  
  2151.     memset(&lf,0,sizeof(LOGFONT));
  2152.     lf.lfPitchAndFamily = FF_SWISS;
  2153.     lf.lfCharSet = IntlGetLfCharset(csid);
  2154.     if (csid == CS_LATIN1)
  2155.          _tcscpy(lf.lfFaceName, "MS Sans Serif");
  2156.     else
  2157.          _tcscpy(lf.lfFaceName, IntlGetUIPropFaceName(csid));
  2158.        lf.lfHeight = -MulDiv(9,pdc.GetDeviceCaps(LOGPIXELSY), 72);
  2159.     m_hRegFont = theApp.CreateAppFont( lf );
  2160.     lf.lfWeight = 700;
  2161.     m_hBoldFont = theApp.CreateAppFont( lf );
  2162.     lf.lfWeight = 0;
  2163.     lf.lfItalic = TRUE;
  2164.     m_hItalFont = theApp.CreateAppFont( lf );
  2165.     TEXTMETRIC tm;
  2166.  
  2167.     HFONT pOldFont = (HFONT) pdc.SelectObject ( m_hBoldFont );
  2168.     pdc.GetTextMetrics ( &tm );
  2169.     pdc.SelectObject(pOldFont);
  2170.     m_cxChar = tm.tmAveCharWidth;
  2171.     m_cyChar = tm.tmHeight + tm.tmExternalLeading;
  2172.     m_itemHeight = m_cyChar;
  2173.     if ( m_pIImage )
  2174.         InitializeItemHeight(max(m_pIImage->GetImageHeight(),m_itemHeight));
  2175.  
  2176.     Invalidate();
  2177.  
  2178.     m_pTip->SetCSID(m_iCSID);
  2179. }
  2180.  
  2181.  
  2182. int COutliner::LineFromPoint (POINT point)
  2183. {
  2184.     int iLine = m_iTopLine + (point.y / m_itemHeight);
  2185.  
  2186.     // Figure out which portion of the line the point is on.
  2187.     int iDiff = point.y - ((iLine - m_iTopLine) *m_itemHeight);
  2188.     
  2189.     int iOldLineHalf = m_iDragSelectionLineHalf, iOldLineThird = m_iDragSelectionLineThird;
  2190.     m_iDragSelectionLineHalf = (iDiff <= m_itemHeight / 2) ? 1 : 2;
  2191.     m_iDragSelectionLineThird = (iDiff <= m_itemHeight / 3) ? 1 : (iDiff <= 2 * (m_itemHeight/3)) ? 2 : 3;
  2192.     
  2193.     if(m_iTopLine !=0)
  2194.         int i =0;
  2195.     m_bDragSectionChanged = (iOldLineHalf != m_iDragSelectionLineHalf || iOldLineThird !=m_iDragSelectionLineThird);
  2196.  
  2197.     return ( iLine );
  2198. }
  2199.  
  2200. DROPEFFECT COutliner::DropSelect (int iLineNo, COleDataObject *object )
  2201. {
  2202.     if (iLineNo >= m_iTotalLines)
  2203.         return DROPEFFECT_NONE;
  2204.     else if (iLineNo == m_iDragSelection && !m_bDragSectionChanged)
  2205.         return DROPEFFECT_MOVE;
  2206.  
  2207.     if (m_iDragSelection != -1)
  2208.         InvalidateLine (m_iDragSelection);
  2209.  
  2210.     m_iDragSelection = iLineNo;
  2211.     InvalidateLine (m_iDragSelection);
  2212.     
  2213.     return DROPEFFECT_MOVE;
  2214. }
  2215.  
  2216. void COutliner::EndDropSelect(void)
  2217. {
  2218.     if (m_iDragSelection != -1) {
  2219.         m_iDragSelection = -1;
  2220.         m_iDragSelectionLineHalf = -1;
  2221.         m_iDragSelectionLineThird = -1;
  2222.         m_bDragSectionChanged = FALSE;
  2223.         Invalidate();
  2224.         UpdateWindow();
  2225.     }
  2226. }
  2227.  
  2228. COleDataSource *COutliner::GetDataSource(void)
  2229. {
  2230.     return NULL;
  2231. }
  2232.  
  2233. void COutliner::InitiateDragDrop(void)
  2234. {
  2235.     m_bDraggingData = TRUE;
  2236.     COleDataSource * pDataSource = GetDataSource();
  2237.     if ( pDataSource) {
  2238.         DROPEFFECT res = pDataSource->DoDragDrop
  2239.             (DROPEFFECT_COPY | DROPEFFECT_LINK | DROPEFFECT_MOVE | DROPEFFECT_SCROLL);
  2240.         pDataSource->Empty();
  2241.         delete pDataSource;
  2242.     }
  2243.     m_bDraggingData = FALSE;
  2244. }
  2245.  
  2246. BOOL COutliner::RecognizedFormat (COleDataObject * pDataObject)
  2247. {
  2248.     CLIPFORMAT * pFormatList = GetClipFormatList();
  2249.     if (pFormatList != NULL) {
  2250.         while (*pFormatList) {
  2251.             if (pDataObject->IsDataAvailable(*pFormatList))
  2252.                 return TRUE;
  2253.             pFormatList++;
  2254.         }
  2255.     }
  2256.     return FALSE;
  2257. }
  2258.  
  2259. void COutliner::AcceptDrop(int iLineNo, class COleDataObject *pDataObject, 
  2260.                            DROPEFFECT dropEffect)
  2261. {
  2262.  
  2263. }
  2264.  
  2265. CLIPFORMAT * COutliner::GetClipFormatList(void)
  2266. {
  2267.     return NULL;
  2268. }    
  2269.  
  2270. void COutliner::OnSelChanged()
  2271. {
  2272. }
  2273.  
  2274. void COutliner::OnSelDblClk()
  2275. {
  2276. }
  2277.  
  2278. #if defined(XP_WIN32) && _MSC_VER >= 1100
  2279. LONG COutliner::OnHackedMouseWheel(WPARAM wParam, LPARAM lParam)
  2280. {
  2281.     return(OnMouseWheel(wParam << 16, lParam));
  2282. }
  2283.  
  2284. LONG COutliner::OnMouseWheel(WPARAM wParam, LPARAM lParam)
  2285. {
  2286.     //  Increase the delta.
  2287.     m_iWheelDelta += MOUSEWHEEL_DELTA(wParam, lParam);
  2288.  
  2289.     //  Number of lines to scroll.
  2290.     UINT uScroll = intelli.ScrollLines();
  2291.  
  2292.     //  Direction.
  2293.     BOOL bForward = TRUE;
  2294.     if(m_iWheelDelta < 0)   {
  2295.         bForward = FALSE;
  2296.     }
  2297.  
  2298.     //  Scroll bar code to use.
  2299.     UINT uSBCode = SB_LINEUP;
  2300.  
  2301.     if(m_iWheelDelta / WHEEL_DELTA)  {
  2302.         if(uScroll == WHEEL_PAGESCROLL)   {
  2303.             if(bForward)    {
  2304.                 uSBCode = SB_PAGEUP;
  2305.             }
  2306.             else    {
  2307.                 uSBCode = SB_PAGEDOWN;
  2308.             }
  2309.             uScroll = 1;
  2310.         }
  2311.         else    {
  2312.             if(bForward)    {
  2313.                 uSBCode = SB_LINEUP;
  2314.             }
  2315.             else    {
  2316.                 uSBCode = SB_LINEDOWN;
  2317.             }
  2318.         }
  2319.  
  2320.         //  Take off scroll increment.
  2321.         UINT uLoops = 0;
  2322.         while(m_iWheelDelta / WHEEL_DELTA)  {
  2323.             if(bForward)   {
  2324.                 m_iWheelDelta -= WHEEL_DELTA;
  2325.             }
  2326.             else    {
  2327.                 m_iWheelDelta += WHEEL_DELTA;
  2328.             }
  2329.             uLoops++;
  2330.         }
  2331.  
  2332.         //  Do it.
  2333.         if(uLoops)        {
  2334.             OnVScroll(uSBCode, 0, NULL);
  2335.         }
  2336.     }
  2337.  
  2338.     return(1);
  2339. }
  2340. #endif
  2341.  
  2342. //
  2343. // rhp - Added for QA Partner hooks - NO NEED TO I18N/L10N SINCE THIS 
  2344. // IS FOR QA WORK ONLY!!!
  2345. //
  2346. #define        NULL_STRING "<Null>"
  2347.  
  2348. LPCSTR
  2349. NullIt(LPCTSTR inVar)
  2350. {
  2351.     if (!inVar)
  2352.         return NULL_STRING;
  2353.  
  2354.     if (inVar[0] == '\0')
  2355.         return NULL_STRING;
  2356.  
  2357.     return inVar;
  2358. }
  2359.  
  2360. // This is the result of a WM_COPYDATA message. This will be used to send requests
  2361. // into Communicator to get data out of Outliner objects as well as drive the 
  2362. // application for automated testing. The return codes of these call will either be
  2363. // the data/number asked for or just a status of processing the request and getting
  2364. // the information into the share memory segment.
  2365. //
  2366. // The description of the parameters coming into this call are:
  2367. //
  2368. //    wParam = (WPARAM) (HWND) hwnd;            // handle of sending window 
  2369. //    lParam = (LPARAM) (PCOPYDATASTRUCT) pcds; // pointer to structure with data 
  2370. //
  2371. //        typedef struct tagCOPYDATASTRUCT {  // cds  
  2372. //            DWORD dwData;            // the ID of the request
  2373. //            DWORD cbData;            // the size of the argument
  2374. //            PVOID lpData;            // the data (i.e. the pointer/name of shared mem)
  2375. //        } COPYDATASTRUCT; 
  2376. //
  2377. //    The lpData will be NULL for all Win32 calls and it will be a pointer to
  2378. //    the (CSharedData *) structure to fill on Win16
  2379. //
  2380. // Returns: This is call specific. For calls that only return numeric values,
  2381. // the return code is results. For calls that return buffers of data, this is a 
  2382. // status code witht the following meaning:
  2383. //
  2384. //            0 - Problem with the processing.
  2385. //          1 - Everything is ok.
  2386. //
  2387. LONG COutliner::OnProcessOLQAHook(WPARAM wParam, LPARAM lParam)
  2388. {
  2389.     CSharedData    *memChunk = NULL;
  2390.  
  2391.     PCOPYDATASTRUCT     pcds = (PCOPYDATASTRUCT) lParam;
  2392.     if (lParam == NULL)
  2393.     {
  2394.         return(0);
  2395.     }
  2396.  
  2397.     TRACE("OLQAHook Message ID = %d\n", pcds->dwData);
  2398.     switch (pcds->dwData) 
  2399.     {
  2400.     case QA_OLGETCOUNT:
  2401.         return(GetTotalLines());
  2402.         break;
  2403.  
  2404.     case QA_OLGETVISIBLECOUNT:
  2405.         return(GetVisibleColumns());
  2406.         break;
  2407.  
  2408.     case QA_OLGETFOCUSLINE:
  2409.         return(GetFocusLine());
  2410.         break;
  2411.  
  2412.   case QA_OLGETCOLCOUNT:
  2413.         return(GetNumColumns());
  2414.     break;
  2415.  
  2416.   // rhp - new code as of 12/2
  2417.   case QA_OLGETISCOLLAPSED:
  2418.     {
  2419.       DWORD    *dwPtr;
  2420.       
  2421.       dwPtr = (DWORD *)pcds->lpData;
  2422.       return(IsCollapsed( *dwPtr ));
  2423.       break;
  2424.     }
  2425.  
  2426.   case QA_OLGETNUMCHILDREN:
  2427.     {
  2428.       DWORD    *dwPtr;
  2429.       
  2430.       dwPtr = (DWORD *)pcds->lpData;
  2431.       return(GetNumChildren( *dwPtr ));
  2432.       break;
  2433.     }
  2434.  
  2435.   case QA_OLSCROLLINTOVIEW:
  2436.     {
  2437.       DWORD    *dwPtr;
  2438.       
  2439.       dwPtr = (DWORD *)pcds->lpData;
  2440.       ScrollIntoView( *dwPtr );
  2441.       return(1);
  2442.     }
  2443.  
  2444.     case QA_OLSETFOCUSLINE:
  2445.         {
  2446.         DWORD    *dwPtr;
  2447.  
  2448.             dwPtr = (DWORD *)pcds->lpData;
  2449.             SetFocusLine(*dwPtr);
  2450.             SelectItem( *dwPtr );
  2451.             return (1);
  2452.             break;
  2453.         }
  2454.     case QA_OLGETTEXT:
  2455.         {
  2456. #ifdef WIN32
  2457.             memChunk = OpenExistingSharedMemory();
  2458. #else
  2459.             memChunk = (CSharedData *) pcds->lpData;
  2460. #endif
  2461.             if (!memChunk)
  2462.             {
  2463.                 return(0);
  2464.             }
  2465.  
  2466.             DWORD    i;
  2467.             DWORD    lineNumber = GetFocusLine();
  2468.             char    workLine[8192];
  2469.             DWORD    copySize;
  2470.             void    *pLineData = AcquireLineData ( lineNumber ); // Make this a parameter...
  2471.  
  2472.             memset(workLine, 0, sizeof(workLine));
  2473.             for (i=0; i<GetNumColumns(); i++)
  2474.             {
  2475.                 LPCTSTR colText = GetColumnText ( m_pColumn[ i ]->iCommand, pLineData );
  2476.                 if (!colText)
  2477.                     continue;
  2478.  
  2479.                 lstrcat(workLine, NullIt(m_pColumn[ i ]->pHeader));
  2480.                 lstrcat(workLine, "=");
  2481.  
  2482.                 lstrcat(workLine, NullIt(colText));
  2483.                 lstrcat(workLine, "|");
  2484.             }
  2485.  
  2486.             ReleaseLineData(pLineData);
  2487.  
  2488.             //
  2489.             // Make sure we don't do something stupid!
  2490.             //
  2491.             if (strlen((char *)workLine) < memChunk->m_dwSize)
  2492.             {
  2493.                 copySize = strlen((char *)workLine);
  2494.             }
  2495.             else
  2496.             {
  2497.                 copySize = memChunk->m_dwSize;
  2498.             }
  2499.  
  2500.             strncpy((char *) memChunk->m_buf, (char *)workLine, copySize);
  2501.             memChunk->m_buf[copySize] = '\0';
  2502.             memChunk->m_dwBytesUsed = copySize + 1;
  2503.  
  2504.             CloseSharedMemory();
  2505.             break;
  2506.         }
  2507.  
  2508.     default:
  2509.         break;
  2510.     }
  2511.  
  2512.     return(1);
  2513. }
  2514. // rhp
  2515.  
  2516. //////////////////////////////////////////////////////////////////////////////
  2517. // CMSelectOutliner
  2518.  
  2519. CMSelectOutliner::CMSelectOutliner()
  2520. {
  2521.     m_bNoMultiSel = FALSE;
  2522.     m_iShiftAnchor = -1;
  2523.     m_iIndicesSize = 64;
  2524.     m_pIndices = new MSG_ViewIndex[m_iIndicesSize];
  2525.     m_iIndicesCount = 0;
  2526. }
  2527.  
  2528. CMSelectOutliner::~CMSelectOutliner()
  2529. {
  2530.     delete [] m_pIndices;
  2531. }
  2532.  
  2533.  
  2534. void CMSelectOutliner::ClearSelection()
  2535. {
  2536.     int i;
  2537.     for (i = 0; i < m_iIndicesCount; i++ ) {
  2538.         InvalidateLine(CASTINT(m_pIndices[i]));
  2539.     }
  2540.     m_iIndicesCount = 0;
  2541. }
  2542.  
  2543. void CMSelectOutliner::GetSelection( const MSG_ViewIndex *&indices, int &count )
  2544. {
  2545.     indices = m_pIndices;
  2546.     count = m_iIndicesCount;
  2547. }
  2548.  
  2549. void CMSelectOutliner::AddSelection( MSG_ViewIndex iSel )
  2550. {
  2551.     int i;
  2552.  
  2553.     for (i = 0; i < m_iIndicesCount; i++) {
  2554.         if ( m_pIndices[i] == iSel ) {
  2555.             return;
  2556.         }
  2557.     }
  2558.  
  2559.     if (i >= m_iIndicesSize) {
  2560.         // Resize storage array (exponential grow)
  2561.         MSG_ViewIndex *tmp = new MSG_ViewIndex[m_iIndicesSize * 2];
  2562.         memcpy(tmp, m_pIndices, m_iIndicesSize * sizeof(MSG_ViewIndex));
  2563.         delete [] m_pIndices;
  2564.         m_pIndices = tmp;
  2565.         m_iIndicesSize *= 2;
  2566.     }
  2567.     if (iSel >= 0 && iSel < m_iTotalLines) {
  2568.         m_pIndices[i] = iSel;
  2569.         m_iIndicesCount++;
  2570.     }
  2571.  
  2572.     InvalidateLine( CASTINT(iSel) );
  2573. }
  2574.  
  2575. void CMSelectOutliner::RemoveSelection( MSG_ViewIndex iSel )
  2576. {
  2577.     int i, j;
  2578.  
  2579.     for (i = 0, j = 0; i < m_iIndicesCount; i++) {
  2580.         if (m_pIndices[i] == iSel) {
  2581.             InvalidateLine( CASTINT(iSel) );
  2582.         } else {
  2583.             m_pIndices[j] = m_pIndices[i];
  2584.             j++;
  2585.         }
  2586.     }
  2587.     m_iIndicesCount = j;
  2588.     m_iSelection = -1;       
  2589.     m_iFocus = -1;           
  2590. }
  2591.  
  2592. void CMSelectOutliner::RemoveSelectionRange( MSG_ViewIndex iSelBegin, MSG_ViewIndex iSelEnd )
  2593. {
  2594.     int i, j;
  2595.     if ( iSelBegin > iSelEnd ) {
  2596.         MSG_ViewIndex tmp;
  2597.         tmp = iSelEnd;
  2598.         iSelEnd = iSelBegin;
  2599.         iSelBegin = tmp;
  2600.     }
  2601.     for (i = 0, j = 0; i < m_iIndicesCount; i++ ) {
  2602.         if (m_pIndices[i] >= iSelBegin && m_pIndices[i] <= iSelEnd) {
  2603.             InvalidateLine( CASTINT(m_pIndices[i]) );
  2604.         } else {
  2605.             m_pIndices[j] = m_pIndices[i];
  2606.             j++;
  2607.         }
  2608.     }
  2609.     m_iIndicesCount = j;
  2610.     m_iSelection = -1;       
  2611.     m_iFocus = -1;           
  2612. }
  2613.  
  2614. BOOL CMSelectOutliner::IsSelected ( int iLine )
  2615. {
  2616.     int i;
  2617.     for (i = 0; i < m_iIndicesCount; i++) {
  2618.         if ( (int) m_pIndices[i] == iLine ) {
  2619.             return TRUE;
  2620.         }
  2621.     }
  2622.     return FALSE;
  2623. }
  2624.  
  2625. void CMSelectOutliner::SelectRange( MSG_ViewIndex iSelBegin, MSG_ViewIndex iSelEnd )
  2626. {
  2627.     // WHS - we may want to optimize this
  2628.     MSG_ViewIndex i;
  2629.  
  2630.     if ( iSelBegin > iSelEnd ) {
  2631.         MSG_ViewIndex tmp;
  2632.         tmp = iSelEnd;
  2633.         iSelEnd = iSelBegin;
  2634.         iSelBegin = tmp;
  2635.     }
  2636.  
  2637.     for ( i = iSelBegin; i <= iSelEnd; i++ ) {
  2638.         AddSelection(i);
  2639.     }
  2640. }
  2641.  
  2642. BOOL CMSelectOutliner::HandleInsert( MSG_ViewIndex iStart, int32 iCount )
  2643. {
  2644.     int i;
  2645.     for (i = 0; i < m_iIndicesCount; i++) {
  2646.         if ( m_pIndices[i] >= iStart ) {
  2647.             m_pIndices[i] += iCount; // Shift over to make room
  2648.         }
  2649.     }
  2650.     if (m_iSelection >= (int) iStart ) {
  2651.         m_iSelection += CASTINT(iCount);
  2652.     }
  2653.     if (m_iFocus >= (int) iStart ) {
  2654.         m_iFocus += CASTINT(iCount);
  2655.     }
  2656.     if (m_iShiftAnchor >= (int) iStart ) {
  2657.         m_iShiftAnchor += CASTINT(iCount);
  2658.     }
  2659.  
  2660.     m_iTotalLines += CASTINT(iCount);
  2661.  
  2662.     // Invalidate previous line so pipes are drawn correctly
  2663.     if ( iStart ) {
  2664.         iStart--;
  2665.         iCount++;
  2666.     }
  2667.     InvalidateLines( CASTINT(iStart), CASTINT(m_iTotalLines - iStart + iCount));
  2668.  
  2669.     return FALSE;
  2670. }
  2671.  
  2672. BOOL CMSelectOutliner::HandleDelete( MSG_ViewIndex iStart, int32 iCount )
  2673. {
  2674.     BOOL res = FALSE;
  2675.     int i, j;
  2676.  
  2677.     for (i = 0, j = 0; i < m_iIndicesCount; i++) {
  2678.         if ( m_pIndices[i] >= iStart ) {
  2679.             if (m_pIndices[i] < (iStart + iCount)) {
  2680.                 res = TRUE;
  2681.                 continue;
  2682.             } else {
  2683.                 m_pIndices[i] -= iCount; // Shift into gap
  2684.             }
  2685.         }
  2686.         m_pIndices[j] = m_pIndices[i];
  2687.         j++;
  2688.     }
  2689.     m_iIndicesCount = j;
  2690.     if (m_iSelection >= int(iStart) ) {
  2691.         if (m_iSelection < int(iStart + iCount))
  2692.             m_iSelection = int(iStart);
  2693.         else
  2694.             m_iSelection -= CASTINT(iCount);
  2695.  
  2696.         if (m_iSelection >= m_iTotalLines - iCount)
  2697.             m_iSelection = CASTINT(m_iTotalLines - iCount - 1);
  2698.  
  2699.         if (m_iSelection < 0 )
  2700.             m_iSelection = (m_iTotalLines - iCount) > 0 ? 0 : -1;
  2701.     }
  2702.     if (m_iFocus >= int(iStart) ) {
  2703.         if (m_iFocus < int(iStart + iCount))
  2704.             m_iFocus = int(iStart);
  2705.         else
  2706.             m_iFocus -= CASTINT(iCount);
  2707.  
  2708.         if (m_iFocus >= m_iTotalLines - iCount)
  2709.             m_iFocus = CASTINT(m_iTotalLines - iCount - 1);
  2710.  
  2711.         if (m_iFocus < 0)
  2712.             m_iFocus = 0;
  2713.     }
  2714.     if (m_iShiftAnchor >= int(iStart) ) {
  2715.         if (m_iShiftAnchor < int(iStart + iCount))
  2716.             m_iShiftAnchor = int(iStart);
  2717.         else
  2718.             m_iShiftAnchor -= CASTINT(iCount);
  2719.  
  2720.         if (m_iShiftAnchor >= m_iTotalLines - iCount)
  2721.             m_iShiftAnchor = CASTINT(m_iTotalLines - iCount - 1);
  2722.  
  2723.         if (m_iShiftAnchor < 0)
  2724.             m_iShiftAnchor = 0;
  2725.     }
  2726.  
  2727.     m_iTotalLines -= CASTINT(iCount);
  2728.  
  2729.     if (!IsSelected(m_iSelection) && (m_iTotalLines > 0))
  2730.         AddSelection( m_iSelection );
  2731.  
  2732.     // Invalidate previous line so pipes are drawn correctly
  2733.     if ( iStart ) {
  2734.         iStart--;
  2735.         iCount++;
  2736.     }
  2737.     InvalidateLines(CASTINT(iStart), CASTINT(m_iTotalLines - iStart + iCount));
  2738.  
  2739.     return res;
  2740. }
  2741.  
  2742. void CMSelectOutliner::HandleScramble()
  2743. {
  2744.     ASSERT(0); // nothing we can do.
  2745. }
  2746.  
  2747. void CMSelectOutliner::PositionHome( )
  2748. {
  2749.     int iOldFocus = m_iFocus;
  2750.  
  2751.     COutliner::PositionHome();
  2752.  
  2753.     if (iOldFocus != m_iFocus ) {
  2754.         ClearSelection();
  2755.         AddSelection(m_iFocus);
  2756.     }
  2757. }
  2758.  
  2759. void CMSelectOutliner::PositionEnd( )
  2760. {
  2761.     int iOldFocus = m_iFocus;
  2762.  
  2763.     COutliner::PositionEnd();
  2764.  
  2765.     if (iOldFocus != m_iFocus ) {
  2766.         ClearSelection();
  2767.         AddSelection(m_iFocus);
  2768.     }
  2769. }
  2770.  
  2771. void CMSelectOutliner::PositionPrevious( )
  2772. {
  2773.     int iOldFocus = m_iFocus;
  2774.  
  2775.     COutliner::PositionPrevious();
  2776.  
  2777.     if (iOldFocus != m_iFocus ) {
  2778.         ClearSelection();
  2779.         AddSelection(m_iFocus);
  2780.     }
  2781. }
  2782.  
  2783. void CMSelectOutliner::PositionNext( )
  2784. {
  2785.     int iOldFocus = m_iFocus;
  2786.  
  2787.     COutliner::PositionNext();
  2788.  
  2789.     if (iOldFocus != m_iFocus ) {
  2790.         ClearSelection();
  2791.         AddSelection(m_iFocus);
  2792.     }
  2793. }
  2794.  
  2795. void CMSelectOutliner::PositionPageDown( )
  2796. {
  2797.     int iOldFocus = m_iFocus;
  2798.  
  2799.     COutliner::PositionPageDown();
  2800.  
  2801.     if (iOldFocus != m_iFocus ) {
  2802.         ClearSelection();
  2803.         AddSelection(m_iFocus);
  2804.     }
  2805. }
  2806.  
  2807. void CMSelectOutliner::PositionPageUp( )
  2808. {
  2809.     int iOldFocus = m_iFocus;
  2810.  
  2811.     COutliner::PositionPageUp();
  2812.  
  2813.     if (iOldFocus != m_iFocus ) {
  2814.         ClearSelection();
  2815.         AddSelection(m_iFocus);
  2816.     }
  2817. }
  2818.  
  2819. void CMSelectOutliner::SetTotalLines ( int iLines )
  2820. {
  2821.     COutliner::SetTotalLines( iLines );
  2822. }
  2823.  
  2824. void CMSelectOutliner::SelectItem( int iSel, int mode, UINT flags )
  2825. {
  2826.     if ( m_bNoMultiSel ) {
  2827.         flags = 0;
  2828.     }
  2829.  
  2830.     if ( (iSel >= -1) || (iSel < GetTotalLines()) ) {
  2831.  
  2832.         if ( !(flags & MK_SHIFT) || (m_iShiftAnchor == -1 ) )
  2833.             m_iShiftAnchor = iSel;
  2834.  
  2835.         switch ( mode ) {
  2836.         case OUTLINER_LBUTTONDOWN:
  2837.             m_bClearOnRelease = FALSE;
  2838.             m_bSelectOnRelease = FALSE;
  2839.  
  2840.             InvalidateLine( m_iFocus );
  2841.             m_iFocus = m_iSelection = iSel;
  2842.             InvalidateLine( m_iFocus );
  2843.  
  2844.             if ( IsSelected(iSel) ) {
  2845.                 if ( flags & MK_CONTROL ) {
  2846.                     m_bClearOnRelease = TRUE;
  2847.                 } else if ( !( flags & MK_SHIFT) ){
  2848.                     m_bSelectOnRelease = TRUE;
  2849.                 }
  2850.             } else {
  2851.                 if ( !(flags & MK_CONTROL) ) {
  2852.                     ClearSelection();
  2853.                 }
  2854.             }
  2855.  
  2856.             if ( flags & MK_SHIFT ) {
  2857.                 ClearSelection();
  2858.                 SelectRange( m_iShiftAnchor, m_iSelection);
  2859.             } else {
  2860.                 AddSelection(m_iSelection);
  2861.             }
  2862.             break;
  2863.  
  2864.         case OUTLINER_LBUTTONUP:
  2865.             if (m_bClearOnRelease) {
  2866.                 RemoveSelection(iSel);
  2867.             }
  2868.             if ( m_bSelectOnRelease ) {
  2869.                 ClearSelection();
  2870.                 AddSelection(iSel);
  2871.             }
  2872.             OnSelChanged();
  2873.             m_iLastSelected = iSel;        
  2874.             m_bClearOnRelease = FALSE;
  2875.             m_bSelectOnRelease = FALSE;
  2876.             break;
  2877.  
  2878.         case 0:
  2879.             ASSERT(0);
  2880.  
  2881.         case OUTLINER_KEYDOWN:
  2882.             InvalidateLine( m_iFocus );
  2883.             m_iFocus = m_iSelection = iSel;
  2884.             InvalidateLine( m_iFocus );
  2885.             ClearSelection();
  2886.             if ( flags & MK_SHIFT ) {
  2887.                 SelectRange( m_iShiftAnchor, m_iSelection);
  2888.             } else {
  2889.                 AddSelection(m_iSelection);
  2890.             }
  2891.             if (m_iLastSelected == -1)
  2892.             {
  2893.                 OnSelChanged();
  2894.                 m_iLastSelected = m_iSelection;
  2895.             }
  2896.             m_bClearOnRelease = FALSE;
  2897.             m_bSelectOnRelease = FALSE;
  2898.             break;
  2899.  
  2900.         case OUTLINER_RBUTTONDOWN:
  2901.             if (!IsSelected( iSel )) {
  2902.                 InvalidateLine( m_iFocus );
  2903.                 m_iFocus = m_iSelection = iSel;
  2904.                 InvalidateLine( m_iFocus );
  2905.                 ClearSelection();
  2906.                 AddSelection( m_iSelection );
  2907.                 OnSelChanged();
  2908.                 m_iLastSelected = m_iSelection;
  2909.             }
  2910.             break;
  2911.  
  2912.         case OUTLINER_SET:
  2913.             InvalidateLine( m_iFocus );
  2914.             m_iFocus = m_iSelection = iSel;
  2915.             InvalidateLine( m_iFocus );
  2916.             if (!(flags & MK_CONTROL)) {
  2917.                 ClearSelection();
  2918.             }
  2919.             AddSelection(m_iSelection);
  2920.             m_bClearOnRelease = FALSE;
  2921.             m_bSelectOnRelease = FALSE;
  2922.         
  2923.         case OUTLINER_TIMER:
  2924.             OnSelChanged();
  2925.             m_iLastSelected = m_iSelection;
  2926.             break;
  2927.  
  2928.         case OUTLINER_RETURN:
  2929.             if (!IsSelected(iSel)) {
  2930.                 InvalidateLine( m_iFocus );
  2931.                 m_iFocus = m_iSelection = iSel;
  2932.                 InvalidateLine( m_iFocus );
  2933.                 if (!(flags & MK_CONTROL)) {
  2934.                     ClearSelection();
  2935.                 }
  2936.                 AddSelection(m_iSelection);
  2937.                 break;
  2938.             }
  2939.  
  2940.         case OUTLINER_LBUTTONDBLCLK:
  2941.             OnSelDblClk();
  2942.             m_bClearOnRelease = FALSE;
  2943.             m_bSelectOnRelease = FALSE;
  2944.             break;
  2945.  
  2946.         default:
  2947.             ASSERT("What kind of garbage are you passing me?" == NULL);
  2948.         }
  2949.         UpdateWindow();
  2950.     }
  2951. }
  2952.  
  2953. void CMSelectOutliner::SelectRange( int iStart, int iEnd, BOOL bNotify )
  2954. {
  2955.     if ( iStart == -1 ) {
  2956.         ClearSelection();
  2957.     } else { 
  2958.         if (iEnd == -1) {
  2959.             iEnd = m_iTotalLines - 1;
  2960.         }
  2961.         SelectRange( iStart, iEnd );
  2962.     }
  2963.     if ( bNotify )
  2964.         OnSelChanged();
  2965. }
  2966.  
  2967. //////////////////////////////////////////////////////////////////////////////
  2968. // COutlinerDropTarget
  2969.  
  2970. COutlinerDropTarget::COutlinerDropTarget( COutliner *pOutliner )
  2971. {
  2972.     ASSERT(pOutliner);
  2973.     m_pOutliner = pOutliner;
  2974.     m_dwOldTicks = 0;
  2975. }
  2976.  
  2977. void COutlinerDropTarget::DragScroll( BOOL bBackwards )
  2978. {
  2979.     DWORD dwTicks = GetTickCount();
  2980.     if (!dwTicks || (dwTicks - m_dwOldTicks) > m_pOutliner->GetDragHeartbeat()) {
  2981.         if (dwTicks) {
  2982.             m_pOutliner->OnVScroll(bBackwards ? SB_LINEUP : SB_LINEDOWN, 0, 0);
  2983.             m_pOutliner->UpdateWindow();
  2984.         }
  2985.         m_dwOldTicks = dwTicks;
  2986.     }
  2987. }
  2988.  
  2989. BOOL COutlinerDropTarget::OnDrop(
  2990.     CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point)
  2991. {
  2992.     m_dwOldTicks = 0;
  2993.  
  2994.     if(!pDataObject || !m_pOutliner)
  2995.         return(FALSE);
  2996.  
  2997.     if (!m_pOutliner->RecognizedFormat(pDataObject))
  2998.         return FALSE;
  2999.  
  3000.     m_pOutliner->m_ptHit = point;
  3001.  
  3002.     m_pOutliner->AcceptDrop( m_pOutliner->GetDropLine(), pDataObject, dropEffect);
  3003.     m_pOutliner->EndDropSelect();
  3004.  
  3005.     return(TRUE);
  3006. }
  3007.  
  3008.  
  3009. DROPEFFECT COutlinerDropTarget::OnDragEnter(
  3010.     CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
  3011. {
  3012.     DROPEFFECT res = OnDragOver(pWnd, pDataObject, dwKeyState, point);
  3013.  
  3014.     if ( res != DROPEFFECT_NONE) {
  3015.         m_pOutliner->Invalidate();
  3016.         m_pOutliner->UpdateWindow();
  3017.     }
  3018.  
  3019.     return res;
  3020. }
  3021.  
  3022. DROPEFFECT COutlinerDropTarget::OnDragOver(
  3023.     CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
  3024. {
  3025.     DROPEFFECT effect = DROPEFFECT_NONE;
  3026.  
  3027.     if (m_pOutliner->RecognizedFormat(pDataObject)) {
  3028.         RECT rect;
  3029.         pWnd->GetClientRect(&rect);
  3030.  
  3031.         if ( point.y < m_pOutliner->m_itemHeight ) {
  3032.             DragScroll(TRUE);
  3033.             effect |= DROPEFFECT_SCROLL;
  3034.         } else if ( point.y > ( rect.bottom - m_pOutliner->m_itemHeight ) ) {
  3035.             DragScroll(FALSE);
  3036.             effect |= DROPEFFECT_SCROLL;
  3037.         } else {
  3038.             m_dwOldTicks = 0;
  3039.         }
  3040.  
  3041.         m_pOutliner->m_ptHit = point;
  3042.  
  3043.         effect |= m_pOutliner->DropSelect(m_pOutliner->LineFromPoint(point), pDataObject);
  3044.  
  3045.         // Default is to move
  3046.         if ( ( effect & DROPEFFECT_MOVE) && (dwKeyState & MK_CONTROL) )
  3047.             effect = (effect & ~DROPEFFECT_MOVE) | DROPEFFECT_COPY;
  3048.     }
  3049.     return effect;
  3050. }
  3051.  
  3052. void COutlinerDropTarget::OnDragLeave(CWnd* pWnd)
  3053. {
  3054.     m_pOutliner->EndDropSelect();
  3055. }
  3056.                                            
  3057. #ifdef _WIN32
  3058. DROPEFFECT COutlinerDropTarget::OnDragScroll(
  3059.     CWnd* pWnd, DWORD dwKeyState, CPoint point)
  3060. #else    
  3061. BOOL COutlinerDropTarget::OnDragScroll(
  3062.     CWnd* pWnd, DWORD dwKeyState, CPoint point)
  3063. #endif
  3064. {
  3065.     return COleDropTarget::OnDragScroll(pWnd, dwKeyState, point);
  3066. }
  3067. //////////////////////////////////////////////////////////////////////////////
  3068. // COutlinerParent
  3069.  
  3070. void COutlinerParent::SetOutliner ( COutliner * pOutliner ) 
  3071.     m_pOutliner = pOutliner; 
  3072. }
  3073.  
  3074. void COutlinerParent::InvalidatePusher()
  3075. {
  3076.     RECT rect;
  3077.     GetClientRect(&rect);
  3078.     rect.left = rect.right - m_iPusherWidth;
  3079.     rect.bottom = m_iHeaderHeight;
  3080.     InvalidateRect(&rect);
  3081. }
  3082.  
  3083. int COutlinerParent::TestPusher( POINT &pt )
  3084. {
  3085.     RECT rect;
  3086.     GetClientRect(&rect);
  3087.     rect.left = rect.right - m_iPusherWidth;
  3088.     rect.bottom = m_iHeaderHeight;
  3089.     if (::PtInRect(&rect, pt)) {
  3090.         switch(m_iPusherState) {
  3091.         case pusherLeft:
  3092.         case pusherRight:
  3093.         case pusherLeftRight:
  3094.             rect.right = rect.left + (rect.right - rect.left) / 2;
  3095.             if (::PtInRect(&rect, pt)) {
  3096.                 return pusherLeft;
  3097.             } else {
  3098.                 return pusherRight;
  3099.             }
  3100.         }
  3101.     }
  3102.     return pusherNone;
  3103. }
  3104.  
  3105. BEGIN_MESSAGE_MAP(COutlinerParent, CWnd)
  3106.     ON_WM_PAINT ( )
  3107.     ON_WM_CREATE ( )
  3108.     ON_WM_SIZE ( )    
  3109.     ON_WM_SETFOCUS ( )
  3110.     ON_WM_KEYDOWN ( )
  3111.     ON_WM_ERASEBKGND ( )
  3112.     ON_WM_MOUSEMOVE ( )
  3113.     ON_WM_LBUTTONDOWN ( )
  3114.     ON_WM_LBUTTONUP ( )
  3115.     ON_WM_SETCURSOR ( )
  3116. END_MESSAGE_MAP()
  3117.  
  3118. class CNSOutlinerParentFactory :  public  CGenericFactory
  3119. {
  3120. public:
  3121.     CNSOutlinerParentFactory();
  3122.     ~CNSOutlinerParentFactory();
  3123.     STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter,REFIID refiid, LPVOID * ppvObj);
  3124. };
  3125.  
  3126. CNSOutlinerParentFactory::CNSOutlinerParentFactory()
  3127. {
  3128.    ApiApiPtr(api);
  3129.     api->RegisterClassFactory(APICLASS_OUTLINERPARENT,this);
  3130. }
  3131.  
  3132. CNSOutlinerParentFactory::~CNSOutlinerParentFactory()
  3133. {
  3134. }
  3135.  
  3136. STDMETHODIMP CNSOutlinerParentFactory::CreateInstance(
  3137.     LPUNKNOWN pUnkOuter,
  3138.     REFIID refiid,
  3139.     LPVOID * ppvObj)
  3140. {
  3141.     COutlinerParent * pParent = new COutlinerParent;
  3142.     *ppvObj = (LPVOID)((LPUNKNOWN)pParent);
  3143.     return NOERROR;
  3144. }
  3145.  
  3146. DECLARE_FACTORY(CNSOutlinerParentFactory);
  3147.  
  3148. COutlinerParent::COutlinerParent ( ) 
  3149. {
  3150.     m_bResizeArea = FALSE;
  3151.     m_bResizeColumn = FALSE;
  3152.     m_bHeaderSelected = FALSE;
  3153.     m_bDraggingHeader = FALSE;
  3154.     m_idColHit = 0;
  3155.     m_iColHit = -1;
  3156.     m_iColLoser = -1;
  3157.     m_bHasBorder = FALSE;
  3158.     m_bDisableHeaders = FALSE;
  3159.     m_bEnableFocusFrame = FALSE;
  3160.     m_pOutliner = NULL;
  3161.     m_hToolFont = NULL;
  3162.     m_hbmDrag = NULL;
  3163.     m_hdcDrag = NULL;
  3164.     m_iHeaderHeight = 0;
  3165.     m_iPusherRgn = pusherNone;
  3166.     m_iPusherHit = pusherNone;
  3167.  
  3168.     ApiApiPtr(api);
  3169.     m_pUnkImage = api->CreateClassInstance(
  3170.         APICLASS_IMAGEMAP,NULL,(APISIGNATURE)IDB_COLUMN);
  3171.     m_pUnkImage->QueryInterface(IID_IImageMap,(LPVOID*)&m_pIImage);
  3172.     ASSERT(m_pIImage);
  3173.     if (!m_pIImage->GetResourceID())
  3174.         m_pIImage->Initialize(IDB_COLUMN,8,8);
  3175. }
  3176.  
  3177. COutlinerParent::~COutlinerParent ( )
  3178. {
  3179.     if (m_hToolFont) {
  3180.         theApp.ReleaseAppFont(m_hToolFont);
  3181.     }
  3182.     if ( m_hdcDrag )
  3183.         VERIFY(::DeleteDC( m_hdcDrag ));
  3184.     if ( m_hbmDrag )
  3185.         VERIFY(::DeleteObject( m_hbmDrag ));
  3186.  
  3187.     delete m_pOutliner;
  3188.     if (m_pUnkImage) {
  3189.         if (m_pIImage)
  3190.             m_pUnkImage->Release();
  3191.     }
  3192. }
  3193.  
  3194. BOOL COutlinerParent::ResizeClipCursor()
  3195. {
  3196.     CFont *pOldFont = NULL;
  3197.     CDC *pDC = m_pOutliner->GetDC();
  3198.     if( GetFont() ) 
  3199.     {
  3200.         pOldFont = pDC->SelectObject( GetFont() );
  3201.     }
  3202.     CSize csMinWidth = pDC->GetTextExtent( "W", _tcslen( "W" ) );
  3203.     csMinWidth.cx++;
  3204.     if( pOldFont ) 
  3205.     {
  3206.         pDC->SelectObject( pOldFont );
  3207.     }
  3208.     m_pOutliner->ReleaseDC( pDC );
  3209.  
  3210.     int iLeft = csMinWidth.cx; //max( m_pOutliner->m_pColumn[m_iColHit]->iMinColSize, csMinWidth.cx );
  3211.     int iRight = 0;
  3212.     for( int i = 0; i < m_pOutliner->m_iVisColumns; i++ )
  3213.     {
  3214.         if( i < m_iColHit )
  3215.         {
  3216.             iLeft += m_pOutliner->m_pColumn[i]->iCol;
  3217.         }
  3218.         else if( i > m_iColHit )
  3219.         {
  3220.             if( m_pOutliner->m_pColumn[i]->cType == ColumnVariable )
  3221.             {
  3222.                 iRight += csMinWidth.cx; //max( m_pOutliner->m_pColumn[i]->iMinColSize, csMinWidth.cx );
  3223.             }
  3224.             else
  3225.             {
  3226.                 iRight += m_pOutliner->m_pColumn[i]->iCol;
  3227.             }
  3228.         }
  3229.     }
  3230.     iRight = m_pOutliner->m_iTotalWidth - iRight;
  3231.     if( iRight < iLeft )
  3232.     {
  3233.        iRight = iLeft;
  3234.     }
  3235.     RECT rcClip = { iLeft, 0, iRight, m_iHeaderHeight };
  3236.     MapWindowPoints( CWnd::FromHandle( HWND_DESKTOP ), &rcClip );
  3237.     
  3238.    #ifdef _WIN32
  3239.     return ClipCursor( &rcClip );
  3240.    #else
  3241.     return TRUE;
  3242.    #endif
  3243. }
  3244.  
  3245. BOOL COutlinerParent::TestCol( POINT &pt, int &iCol )
  3246. {
  3247.     iCol = -1;
  3248.     int i;
  3249.     BOOL res = FALSE;
  3250.     RECT rc, rcResize, rcClient;
  3251.  
  3252.     m_bResizeArea = FALSE;
  3253.  
  3254.     GetClientRect(&rcClient);
  3255.  
  3256.     rc.top = rcResize.top = 0;
  3257.     rc.bottom = rcResize.bottom = m_iHeaderHeight;
  3258.     rc.left = 0;
  3259.     rc.right = 0;
  3260.  
  3261.     for ( i = 0; i < m_pOutliner->m_iVisColumns; i++ )
  3262.     {
  3263.         rc.left = rc.right;
  3264.         rc.right = rc.left + m_pOutliner->m_pColumn[ i ]->iCol;
  3265.  
  3266.         if (rc.right > (rcClient.right - m_iPusherWidth)) {
  3267.             rc.right = rcClient.right - m_iPusherWidth;
  3268.         }
  3269.  
  3270.         if ( i < m_pOutliner->m_iVisColumns - 1 ) {
  3271.             rcResize.left = rc.right - 4;
  3272.             rcResize.right = rc.right + 4;
  3273.  
  3274.             if ( ::PtInRect( &rcResize, pt ) ) {
  3275.                 m_bResizeArea = TRUE;
  3276.                 m_iColResize = i;
  3277.             }
  3278.         }
  3279.  
  3280.         if ( ::PtInRect( &rc, pt ) ) {
  3281.             m_rcTest = rc;
  3282.             iCol = i;
  3283.             res = TRUE;
  3284.         }
  3285.     }
  3286.     return res;
  3287. }
  3288.  
  3289. void COutlinerParent::GetColumnRect( int iCol, RECT &rc )
  3290. {
  3291.     GetClientRect(&rc);
  3292.     if (m_bEnableFocusFrame)
  3293.     {
  3294.         rc.top = 1;
  3295.         rc.left = 1;
  3296.         rc.right = 1;
  3297.     }
  3298.     else
  3299.     {
  3300.         rc.left = 0;
  3301.         rc.right = 0;
  3302.     }
  3303.     rc.bottom = m_iHeaderHeight;
  3304.     if ( iCol >= 0 && iCol < m_pOutliner->m_iVisColumns ) {
  3305.         for (int i = 0; i <= iCol; i++) {
  3306.             rc.left = rc.right;
  3307.             rc.right += m_pOutliner->m_pColumn[ i ]->iCol;
  3308.         }
  3309.     }
  3310. }
  3311.  
  3312. void COutlinerParent::InvalidateColumn( int iCol )
  3313. {
  3314.     RECT rc;
  3315.     GetColumnRect( iCol, rc );
  3316.     InvalidateRect( &rc );
  3317. }
  3318.  
  3319. void COutlinerParent::UpdateFocusFrame()
  3320. {
  3321.     if (m_bEnableFocusFrame)
  3322.     {
  3323.         RECT clientRect;
  3324.         GetClientRect(&clientRect);
  3325.         InvalidateRect(&clientRect, FALSE);
  3326.         ::InflateRect(&clientRect, -1, -1);
  3327.         clientRect.top = m_iHeaderHeight + 1;
  3328.         ValidateRect(&clientRect);
  3329.         UpdateWindow();
  3330.     }
  3331. }
  3332.  
  3333. BOOL COutlinerParent::PreTranslateMessage(MSG* pMsg)
  3334. {
  3335.     if (pMsg->message >= WM_MOUSEFIRST && pMsg->message <= WM_MOUSELAST)
  3336.         m_wndTip.RelayEvent(pMsg);
  3337.     
  3338.     return CWnd::PreTranslateMessage(pMsg);
  3339. }
  3340.  
  3341. int COutlinerParent::OnCreate ( LPCREATESTRUCT lpCreateStruct )
  3342. {
  3343.     int iRetVal = (int) Default();
  3344.  
  3345.     if (m_pOutliner = GetOutliner ( ) ) {
  3346.         CClientDC pdc ( this );
  3347.         int m_rescsid = INTL_CharSetNameToID(INTL_ResourceCharSet());
  3348.         LOGFONT lf;
  3349.         memset(&lf,0,sizeof(LOGFONT));
  3350.         lf.lfPitchAndFamily = FF_SWISS;
  3351.         lf.lfCharSet = IntlGetLfCharset(m_rescsid);  // Global lfCharSet
  3352.         if (m_rescsid == CS_LATIN1)
  3353.             strcpy(lf.lfFaceName, "MS Sans Serif");
  3354.         else
  3355.              strcpy(lf.lfFaceName, IntlGetUIPropFaceName(m_rescsid));
  3356.         lf.lfHeight = -MulDiv(9,pdc.GetDeviceCaps(LOGPIXELSY), 72);
  3357.         m_hToolFont = theApp.CreateAppFont( lf );
  3358.  
  3359.         TEXTMETRIC tm;
  3360.         HFONT hOldFont = (HFONT) pdc.SelectObject ( m_hToolFont );
  3361.         pdc.GetTextMetrics ( &tm );
  3362.         pdc.SelectObject ( hOldFont );
  3363.  
  3364.         m_iHeaderHeight = tm.tmHeight + tm.tmExternalLeading + 4;
  3365.         m_cxChar = tm.tmAveCharWidth;
  3366.  
  3367.         LPCTSTR lpszClass = NULL;
  3368.         m_pOutliner->CreateEx ( 0, lpszClass, NULL, 
  3369.             ( m_bHasBorder ? WS_BORDER : 0 )|WS_VISIBLE|WS_CHILD|WS_CLIPCHILDREN|WS_CLIPSIBLINGS, 
  3370.                                 0, 0, 0, 0, this->m_hWnd, lpCreateStruct->hMenu );
  3371.  
  3372.         m_wndTip.Create(this);
  3373.         m_wndTip.AddTool(this, IDS_SHOWHIDECOLUMNS, CRect(0,0,0,0), 1);
  3374.         m_wndTip.Activate(TRUE);
  3375.     } else {
  3376.         iRetVal = -1;
  3377.     }
  3378.     m_iPusherWidth = GetSystemMetrics(SM_CXVSCROLL);
  3379.     m_iPusherWidth = m_iPusherWidth > 20 ? m_iPusherWidth : 20;
  3380.  
  3381.     return iRetVal;
  3382. }
  3383.  
  3384. void COutlinerParent::OnSize ( UINT nType, int cx, int cy )
  3385. {
  3386.     if ( m_pOutliner )
  3387.     {
  3388.         m_pOutliner->m_iTotalWidth = cx - m_iPusherWidth;
  3389.         if (m_bEnableFocusFrame)
  3390.         {
  3391.             m_pOutliner->MoveWindow ( 1,
  3392.                                       m_bDisableHeaders ? 0 : m_iHeaderHeight, 
  3393.                                       cx - 2,
  3394.                                       cy - ( m_bDisableHeaders ? 1 : m_iHeaderHeight + 1 ), TRUE );
  3395.         }
  3396.         else
  3397.         {
  3398.             m_pOutliner->MoveWindow ( 0,
  3399.                                       m_bDisableHeaders ? 0 : m_iHeaderHeight, 
  3400.                                       cx,
  3401.                                       cy - ( m_bDisableHeaders ? 0 : m_iHeaderHeight ), TRUE );
  3402.         }
  3403.         m_wndTip.SetToolRect(this, 1, CRect(cx - m_iPusherWidth, 0, cx, m_iHeaderHeight));
  3404.     }
  3405. }
  3406.  
  3407. void COutlinerParent::OnKeyDown ( UINT nChar, UINT nRepCnt, UINT nFlags )
  3408. {
  3409.     if ( m_pOutliner )
  3410.         m_pOutliner->OnKeyDown ( nChar, nRepCnt, nFlags );
  3411.     else
  3412.         Default();
  3413. }
  3414.  
  3415. void COutlinerParent::OnSetFocus ( CWnd * pOldWnd )
  3416. {
  3417.     Default();
  3418.  
  3419.     if ( m_pOutliner )
  3420.         m_pOutliner->SetFocus ( );
  3421. }
  3422.  
  3423. void COutlinerParent::OnLButtonDown( UINT nFlags, CPoint point )
  3424. {
  3425.     if ( m_pOutliner )
  3426.     {
  3427.         SetCapture ( );
  3428.         m_ptHit = point;
  3429.  
  3430.         if( m_bResizeArea ) 
  3431.         {
  3432.             m_bResizeColumn = TRUE;
  3433.             
  3434.             ResizeClipCursor();
  3435.         } 
  3436.         else 
  3437.         {
  3438.             int iCol = 0;
  3439.             if (TestCol( point, iCol )) {
  3440.                 m_rcDrag = m_rcHit = m_rcTest;
  3441.                 m_bHeaderSelected = TRUE;
  3442.                 m_iColHit = iCol;
  3443.                 m_idColHit = m_pOutliner->m_pColumn[ iCol ]->iCommand;
  3444.  
  3445.                 if ( m_pOutliner->m_pColumn[ iCol ]->bIsButton ) {
  3446.                      m_pOutliner->m_pColumn[ iCol ]->bDepressed = TRUE;
  3447.                     InvalidateColumn ( iCol );
  3448.                 }
  3449.             }
  3450.             int iTestPush = TestPusher(point);
  3451.             if (iTestPush & m_iPusherState) {
  3452.                 m_iPusherHit = m_iPusherRgn = iTestPush;
  3453.                 InvalidatePusher();
  3454.                 UpdateWindow();
  3455.             }
  3456.         }
  3457.     }
  3458.     Default();
  3459. }
  3460.  
  3461. void COutlinerParent::OnLButtonUp( UINT nFlags, CPoint point )
  3462. {
  3463.     if ( GetCapture() != this )
  3464.         return;
  3465.  
  3466.     ReleaseCapture();
  3467.     ClipCursor( NULL );
  3468.     
  3469.     m_bHeaderSelected = FALSE;
  3470.  
  3471.     if ( m_bResizeColumn )
  3472.     {
  3473.         m_bResizeColumn = FALSE;
  3474.         m_bResizeArea = FALSE;
  3475.         return;
  3476.     }
  3477.  
  3478.     if ( m_bDraggingHeader ) {
  3479.         CDC *pDC = GetDC();
  3480. //        pDC->DrawFocusRect(&m_rcDrag);
  3481.         ::BitBlt( pDC->m_hDC,
  3482.                   m_rcDrag.left, 
  3483.                   m_rcDrag.top,
  3484.                   m_rcDrag.right - m_rcDrag.left,
  3485.                   m_rcDrag.bottom - m_rcDrag.top,
  3486.                   m_hdcDrag,
  3487.                   0,
  3488.                   0,
  3489.                   SRCINVERT );
  3490.         VERIFY(::DeleteDC( m_hdcDrag ));
  3491.         m_hdcDrag = NULL;
  3492.         VERIFY(::DeleteObject( m_hbmDrag ));
  3493.         m_hbmDrag = NULL;
  3494.         ReleaseDC(pDC);
  3495.     }
  3496.  
  3497.     if ( m_iColHit != -1 && m_pOutliner->m_pColumn[ m_iColHit ]->bDepressed ) {
  3498.         if ( !m_bDraggingHeader ) {
  3499.             ColumnCommand ( m_pOutliner->m_pColumn[ m_iColHit ]->iCommand );
  3500.         } 
  3501.         m_pOutliner->m_pColumn[ m_iColHit ]->bDepressed = FALSE;
  3502.         InvalidateColumn( m_iColHit );
  3503.     }
  3504.  
  3505.     m_bDraggingHeader = FALSE;
  3506.  
  3507.     if ( m_iPusherHit ) {
  3508.         m_iPusherRgn = TestPusher(point);
  3509.         if ( m_iPusherRgn == m_iPusherHit) {
  3510.             RECT rectClient;
  3511.             GetClientRect(&rectClient);
  3512.             switch (m_iPusherHit) {
  3513.             case pusherLeft:
  3514.                 if ( m_iPusherState & pusherLeft ) {
  3515.                     m_pOutliner->m_iVisColumns++;
  3516.                     m_pOutliner->OnSize ( 0, 
  3517.                                           rectClient.right,
  3518.                                           rectClient.bottom - ( m_bDisableHeaders ? 0 : m_iHeaderHeight ) );
  3519.                     Invalidate();
  3520.                     m_pOutliner->Invalidate();
  3521.                 }
  3522.                 break;
  3523.             case pusherRight:
  3524.                 if ( m_iPusherState & pusherRight ) {
  3525.                     m_pOutliner->m_iVisColumns--;
  3526.                     m_pOutliner->OnSize ( 0, 
  3527.                                           rectClient.right,
  3528.                                           rectClient.bottom - ( m_bDisableHeaders ? 0 : m_iHeaderHeight ) );
  3529.                     Invalidate();
  3530.                     m_pOutliner->Invalidate();
  3531.                 }
  3532.                 break;
  3533.             }
  3534.         }
  3535.         m_iPusherRgn = pusherNone;
  3536.         m_iPusherHit = pusherNone;
  3537.     }
  3538. }
  3539.  
  3540. BOOL COutlinerParent::OnSetCursor( CWnd* pWnd, UINT nHitTest, UINT message )
  3541. {
  3542.     POINT pt;
  3543.     GetCursorPos(&pt);
  3544.     ScreenToClient(&pt);
  3545.  
  3546.     if (!CWnd::OnSetCursor( pWnd, nHitTest, message )) {
  3547.         int iCol = -1;
  3548.         if ( nHitTest == HTCLIENT && 
  3549.              TestCol( pt, iCol) && 
  3550.              m_bResizeArea &&
  3551.              m_pOutliner->m_pColumn[ m_iColResize ]->cType == ColumnVariable ) {
  3552.             iCol = m_iColResize;
  3553.             for ( int i = iCol + 1; i < m_pOutliner->m_iVisColumns; i++ ) {
  3554.                 if ( m_pOutliner->m_pColumn[ i ]->cType == ColumnVariable ) {
  3555.                     SetCursor ( theApp.LoadCursor ( AFX_IDC_HSPLITBAR ) );
  3556.                     m_iColLoser = i;
  3557.                     m_iColHit = iCol;
  3558.  
  3559.                     return TRUE;
  3560.                 }
  3561.             }
  3562.         }
  3563.         m_bResizeArea = FALSE;
  3564.  
  3565.         SetCursor ( ::LoadCursor( NULL, IDC_ARROW ) );
  3566.  
  3567.         return TRUE;
  3568.     }
  3569.     return TRUE;
  3570. }    
  3571.  
  3572. void COutlinerParent::OnMouseMove( UINT nFlags, CPoint point )
  3573. {
  3574.     m_pt = point;
  3575.  
  3576.     if (GetCapture() != this)
  3577.         return;
  3578.  
  3579.     int i;
  3580.  
  3581.     if ( m_bResizeColumn ) {
  3582.         int iDelta = point.x - m_ptHit.x;
  3583.  
  3584.         m_ptHit = point;      
  3585.         
  3586.         m_pOutliner->SqueezeColumns( m_iColHit, iDelta );
  3587.          for( i = m_iColHit; i < m_pOutliner->m_iVisColumns; i++ ) 
  3588.         {
  3589.              InvalidateColumn( i );
  3590.         }
  3591.     } else {
  3592.         if ( m_bHeaderSelected ) {
  3593.             if ( abs(point.x - m_ptHit.x) > 3 ) {
  3594.                 m_bDraggingHeader = TRUE;
  3595.                 m_bHeaderSelected = FALSE;
  3596.                 m_pOutliner->m_pColumn[ m_iColHit ]->bDepressed = FALSE;
  3597.                 InvalidateColumn( m_iColHit );
  3598.                 UpdateWindow();
  3599.  
  3600.                 // Create bitmap for dragging header
  3601.                 CDC *pDC = GetDC();
  3602.  
  3603.                 RECT rcBorder;
  3604.                 ::SetRect( &rcBorder, 0, 0, 
  3605.                            m_rcDrag.right - m_rcDrag.left, m_rcDrag.bottom - m_rcDrag.top );
  3606.                 m_hbmDrag = ::CreateBitmap( rcBorder.right, rcBorder.bottom, 1, 1, NULL );
  3607.                 m_hdcDrag = ::CreateCompatibleDC( pDC->m_hDC );
  3608.                 ::SelectObject( m_hdcDrag, m_hbmDrag );
  3609.                 HFONT hOldFont = (HFONT) ::SelectObject ( m_hdcDrag, m_hToolFont );
  3610.                 ::FillRect( m_hdcDrag, &rcBorder, (HBRUSH) GetStockObject( WHITE_BRUSH ) );
  3611.                 ::FrameRect( m_hdcDrag, &rcBorder, (HBRUSH) GetStockObject( BLACK_BRUSH ) );
  3612.                 ::SetBkColor( m_hdcDrag, RGB(255, 255, 255) );
  3613.                 ::SetTextColor( m_hdcDrag, RGB(0, 0, 0) );
  3614.  
  3615.                 DrawColumnHeader( m_hdcDrag, rcBorder, m_iColHit );
  3616.  
  3617.                 // Invert the sucker
  3618.                 ::BitBlt( m_hdcDrag,
  3619.                           0, 0, rcBorder.right, rcBorder.bottom,
  3620.                           m_hdcDrag,
  3621.                           0, 0,
  3622.                           NOTSRCCOPY );
  3623.  
  3624.                 // Initially XOR the bitmap
  3625.                 ::BitBlt( pDC->m_hDC,
  3626.                           m_rcDrag.left, 
  3627.                           m_rcDrag.top,
  3628.                           m_rcDrag.right - m_rcDrag.left,
  3629.                           m_rcDrag.bottom - m_rcDrag.top,
  3630.                           m_hdcDrag,
  3631.                           0,
  3632.                           0,
  3633.                           SRCINVERT );
  3634.  
  3635.                 ReleaseDC(pDC);
  3636.             }
  3637.         }
  3638.             
  3639.         if ( m_bDraggingHeader ) {
  3640.             int iCol;
  3641.             CDC *pDC = GetDC();
  3642.             // Undo the last XOR
  3643.             ::BitBlt( pDC->m_hDC,
  3644.                       m_rcDrag.left, 
  3645.                       m_rcDrag.top,
  3646.                       m_rcDrag.right - m_rcDrag.left,
  3647.                       m_rcDrag.bottom - m_rcDrag.top,
  3648.                       m_hdcDrag,
  3649.                       0,
  3650.                       0,
  3651.                       SRCINVERT );
  3652.             POINT pt;
  3653.             pt.x = point.x;
  3654.             pt.y = 1; // ignore vertical movement
  3655.             if ( TestCol( pt, iCol ) &&
  3656.                  (m_pOutliner->m_pColumn[ iCol ]->iCommand != m_idColHit) ) {
  3657.                 int iWidth = m_pOutliner->m_pColumn[ m_iColHit ]->iCol;
  3658.                 if ( ( iCol < m_iColHit && point.x - m_rcTest.left < iWidth ) ||
  3659.                      ( iCol > m_iColHit && point.x > m_rcTest.right - iWidth ) ) {
  3660.  
  3661.                     // Shove everything down
  3662.  
  3663.                     OutlinerColumn_t *tmp;
  3664.                     tmp = m_pOutliner->m_pColumn[ m_iColHit ];
  3665.                     if (iCol < m_iColHit) {
  3666.                         for (i = m_iColHit; i > iCol; i--) {
  3667.                             m_pOutliner->m_pColumn[i] = m_pOutliner->m_pColumn[i - 1];
  3668.                         }
  3669.                     } else {
  3670.                         for (i = m_iColHit; i < iCol; i++) {
  3671.                             m_pOutliner->m_pColumn[i] = m_pOutliner->m_pColumn[i + 1];
  3672.                         }
  3673.                     }
  3674.                     m_pOutliner->m_pColumn[ iCol ] = tmp;
  3675.  
  3676.                     // Allow the Outliner a chance to respond to the fact that the columns
  3677.                     // have been adjusted.  (Dave H.)
  3678.                     m_pOutliner->ColumnsSwapped();
  3679.  
  3680.                     // Redraw the relevent stuff
  3681.  
  3682.                     int iStart = m_iColHit < iCol ? m_iColHit : iCol;
  3683.                     int iEnd = m_iColHit < iCol ? iCol : m_iColHit;
  3684.  
  3685.                     for ( i = iStart; i <= iEnd; i++) {
  3686.                         m_pOutliner->InvalidateColumn ( i );
  3687.                         InvalidateColumn ( i );
  3688.                     }
  3689.  
  3690.                     m_pOutliner->UpdateWindow();
  3691.                     UpdateWindow();
  3692.                     m_iColHit = iCol;
  3693.                 }
  3694.             }
  3695.             m_rcDrag.left = point.x + (m_rcHit.left - m_ptHit.x);
  3696.             m_rcDrag.right = point.x + (m_rcHit.right - m_ptHit.x);
  3697.  
  3698.             // XOR the header bitmap
  3699.             ::BitBlt( pDC->m_hDC,
  3700.                       m_rcDrag.left, 
  3701.                       m_rcDrag.top,
  3702.                       m_rcDrag.right - m_rcDrag.left,
  3703.                       m_rcDrag.bottom - m_rcDrag.top,
  3704.                       m_hdcDrag,
  3705.                       0,
  3706.                       0,
  3707.                       SRCINVERT );
  3708.             ReleaseDC(pDC);
  3709.         }
  3710.  
  3711.         if ( m_iPusherHit ) {
  3712.             int iTestPush;
  3713.             if ( (iTestPush = TestPusher( point )) != m_iPusherRgn ) {
  3714.                 m_iPusherRgn = iTestPush;
  3715.                 InvalidatePusher();
  3716.                 UpdateWindow();
  3717.             }
  3718.         }
  3719.     }
  3720.     Default();
  3721. }
  3722.  
  3723. void COutlinerParent::DrawButtonRect( HDC hDC, const RECT &rect, BOOL bDepressed )
  3724. {
  3725.     HPEN hBlackPen = (HPEN) ::GetStockObject(BLACK_PEN);
  3726.     HPEN hShadowPen = ::CreatePen( PS_SOLID, 0, GetSysColor ( COLOR_BTNSHADOW ) );
  3727.     HPEN hHighLightPen = ::CreatePen( PS_SOLID, 0, GetSysColor ( COLOR_BTNHIGHLIGHT ) );
  3728.     HPEN hLightPen = NULL;
  3729. #ifdef _WIN32
  3730.     if ( sysInfo.m_bWin4 ) {
  3731.         hLightPen = ::CreatePen( PS_SOLID, 0, GetSysColor( COLOR_3DLIGHT ) );
  3732.     }
  3733. #endif
  3734.  
  3735.     HPEN hOldPen = (HPEN) ::SelectObject ( hDC, bDepressed ? hShadowPen : hBlackPen );
  3736.     ::MoveToEx( hDC, rect.left, rect.bottom - 1, NULL );
  3737.     ::LineTo( hDC, rect.right - 1, rect.bottom - 1 );
  3738.     ::LineTo( hDC, rect.right - 1, rect.top - 1 );
  3739.  
  3740.     if ( !bDepressed )
  3741.     {
  3742.         ::SelectObject( hDC, hShadowPen );
  3743.         ::MoveToEx( hDC, rect.left + 1, rect.bottom - 2, NULL );
  3744.         ::LineTo( hDC, rect.right - 2, rect.bottom - 2 );
  3745.         ::LineTo( hDC, rect.right - 2, rect.top );
  3746.  
  3747.         if ( hLightPen ) {
  3748.             ::SelectObject( hDC, hLightPen );
  3749.         } else { 
  3750.             ::SelectObject( hDC, hHighLightPen );
  3751.         }
  3752.         ::MoveToEx( hDC, rect.left + 1, rect.bottom - 3, NULL );
  3753.         ::LineTo( hDC, rect.left + 1, rect.top + 1 );
  3754.         ::LineTo( hDC, rect.right - 2, rect.top + 1 );
  3755.     }
  3756.  
  3757.     ::SelectObject( hDC, bDepressed ? hShadowPen : hHighLightPen );
  3758.     ::MoveToEx( hDC, rect.left, rect.bottom - 2, NULL );
  3759.     ::LineTo( hDC, rect.left, rect.top );
  3760.     ::LineTo( hDC, rect.right - 1, rect.top );
  3761.  
  3762.     ::SelectObject( hDC, hOldPen );
  3763.  
  3764.     VERIFY( ::DeleteObject( hShadowPen ));
  3765.     VERIFY( ::DeleteObject( hHighLightPen ));
  3766.     if ( hLightPen )
  3767.         VERIFY( ::DeleteObject( hLightPen ));
  3768. }
  3769.  
  3770. void COutlinerParent::DrawColumnHeader( HDC hdc, const RECT &rect, int iCol )
  3771. {
  3772.     CRect rcText = rect;
  3773.     BOOL bDep = m_pOutliner->m_pColumn[ iCol ]->bDepressed &&
  3774.                 m_pOutliner->m_pColumn[ iCol ]->bIsButton;
  3775.  
  3776.     if ( bDep ) {
  3777.         ::OffsetRect(&rcText, 1, 1);
  3778.     }
  3779.  
  3780.     if (!RenderData( m_pOutliner->m_pColumn[ iCol ]->iCommand, rcText, *(CDC::FromHandle(hdc)), 
  3781.                      m_pOutliner->m_pColumn[ iCol ]->pHeader )) {
  3782.         ::InflateRect(&rcText, -4, 0);
  3783.  
  3784.         UINT dwDTFormat = DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER;
  3785.  
  3786.         switch ( m_pOutliner->m_pColumn[ iCol ]->alignment ) {
  3787.         case AlignCenter:
  3788.             dwDTFormat |= DT_CENTER;
  3789.             break;
  3790.         case AlignRight:
  3791.             dwDTFormat |= DT_RIGHT;
  3792.             break;
  3793.         case AlignLeft:
  3794.             dwDTFormat |= DT_LEFT;
  3795.         }
  3796.  
  3797.         WFE_DrawTextEx( 0, hdc, 
  3798.                         (LPTSTR) m_pOutliner->m_pColumn[ iCol ]->pHeader, -1, 
  3799.                         &rcText, dwDTFormat, WFE_DT_CROPRIGHT );
  3800.     }
  3801. }
  3802. void COutlinerParent::OnPaint ( )
  3803. {                            
  3804.     CPaintDC pdc ( this );
  3805.  
  3806.     if ( !m_pOutliner || m_bDisableHeaders )
  3807.         return;
  3808.  
  3809.     int i, offset;
  3810.  
  3811.     // we might use these in the for() loop below --- make sure
  3812.     //  they stay in scope since we don't restore into the CDC until
  3813.     //  the end of the routine
  3814.     HFONT hOldFont = (HFONT) pdc.SelectObject ( m_hToolFont );
  3815.     COLORREF cOldText = pdc.SetTextColor(GetSysColor(COLOR_BTNTEXT));
  3816.     COLORREF cOldBk   = pdc.SetBkColor(GetSysColor(COLOR_BTNFACE));
  3817.  
  3818.     CRect rectClient;
  3819.     GetClientRect ( &rectClient );
  3820.     int iMaxHeaderWidth = rectClient.right - m_iPusherWidth;
  3821.  
  3822.     for ( i = offset = 0; (i < m_pOutliner->m_iVisColumns) && (offset < iMaxHeaderWidth); i++ )
  3823.     {
  3824.         BOOL bDep = m_pOutliner->m_pColumn[ i ]->bDepressed &&
  3825.                     m_pOutliner->m_pColumn[ i ]->bIsButton;
  3826.         CRect rect( offset, 0, m_pOutliner->m_pColumn[ i ]->iCol + offset, m_iHeaderHeight );
  3827.  
  3828.         if (rect.right > iMaxHeaderWidth ) {
  3829.             rect.right = iMaxHeaderWidth;
  3830.         }
  3831.  
  3832.         RECT rcInter;
  3833.         if ( ::IntersectRect ( &rcInter, &pdc.m_ps.rcPaint, &rect ) )
  3834.         {
  3835.             RECT rcText = rect;
  3836.             ::InflateRect(&rcText,-2,-2);
  3837.             ::FillRect(pdc.m_hDC, &rcText, sysInfo.m_hbrBtnFace );
  3838.             DrawColumnHeader( pdc.m_hDC, rcText, i );
  3839.             DrawButtonRect( pdc.m_hDC, rect, bDep );
  3840.         }
  3841.  
  3842.         offset += m_pOutliner->m_pColumn[ i ]->iCol;
  3843.     }
  3844.  
  3845.     // Fill in the gap on the right
  3846.  
  3847.     if (offset < iMaxHeaderWidth) {
  3848.         RECT rect = {offset, 0, iMaxHeaderWidth, m_iHeaderHeight};
  3849.         RECT rcInter;
  3850.  
  3851.         if ( IntersectRect( &rcInter, &pdc.m_ps.rcPaint, &rect ) ) {
  3852.             RECT rcText = rect;
  3853.             ::InflateRect(&rcText,-2,-2);
  3854.             ::FillRect(pdc.m_hDC, &rcText, sysInfo.m_hbrBtnFace );
  3855.             DrawButtonRect( pdc.m_hDC, rect, FALSE );
  3856.         }
  3857.     }
  3858.  
  3859.     CRect rect(rectClient.right - m_iPusherWidth, 0, rectClient.right, m_iHeaderHeight );
  3860.     CRect iRect;
  3861.  
  3862.     if ( iRect.IntersectRect ( &pdc.m_ps.rcPaint, &rect ) ) {
  3863.         int idxImage;
  3864.         ::FillRect ( pdc.m_hDC, &rect, sysInfo.m_hbrBtnFace );
  3865.  
  3866.         m_iPusherState = pusherNone;
  3867.         if ( m_pOutliner->m_iNumColumns > 1 ) {
  3868.             if (m_pOutliner->m_iVisColumns > 1) {
  3869.                 m_iPusherState |= pusherRight;
  3870.             }
  3871.             if (m_pOutliner->m_iVisColumns < m_pOutliner->m_iNumColumns) {
  3872.                 m_iPusherState |= pusherLeft;
  3873.             }
  3874.         }
  3875.  
  3876.         POINT ptBitmap;
  3877.         RECT rect2 = rect;
  3878.  
  3879.         // Draw left pusher
  3880.         rect2.right = (rect.left + rect.right + 1) / 2;
  3881.  
  3882.         ptBitmap.x = (rect2.left + rect2.right + 1) / 2 - 4;
  3883.         ptBitmap.y = (rect2.top + rect2.bottom + 1) / 2 - 4;
  3884.         if ( m_iPusherRgn == pusherLeft ) {
  3885.             ptBitmap.x++;
  3886.             ptBitmap.y++;
  3887.         }
  3888.         idxImage = m_iPusherState & pusherLeft ? 
  3889.                    IDX_PUSHLEFT : IDX_PUSHLEFTI;
  3890.         m_pIImage->DrawImage( idxImage, ptBitmap.x, ptBitmap.y, &pdc, TRUE);
  3891.         DrawButtonRect( pdc.m_hDC, rect2, m_iPusherRgn == pusherLeft );
  3892.         
  3893.         // Draw right pusher
  3894.         rect2.left = rect2.right;
  3895.         rect2.right = rect.right;
  3896.         ptBitmap.x = (rect2.left + rect2.right + 1) / 2 - 4;
  3897.         ptBitmap.y = (rect2.top + rect2.bottom + 1) / 2 - 4;
  3898.         if ( m_iPusherRgn == pusherRight ) {
  3899.             ptBitmap.x++;
  3900.             ptBitmap.y++;
  3901.         }
  3902.          idxImage = m_iPusherState & pusherRight ? 
  3903.                    IDX_PUSHRIGHT : IDX_PUSHRIGHTI;
  3904.         m_pIImage->DrawImage( idxImage, ptBitmap.x, ptBitmap.y, &pdc, TRUE);
  3905.         DrawButtonRect( pdc.m_hDC, rect2, m_iPusherRgn == pusherRight );
  3906.     }
  3907.  
  3908.     pdc.SelectObject ( hOldFont );
  3909.     pdc.SetTextColor ( cOldText );
  3910.     pdc.SetBkColor ( cOldBk );
  3911.  
  3912.     if (m_bEnableFocusFrame)
  3913.     {
  3914.         HBRUSH hBrush = NULL;
  3915.         if (GetFocus() == m_pOutliner)
  3916.             hBrush = ::CreateSolidBrush( GetSysColor( COLOR_HIGHLIGHT ) );
  3917.         else
  3918.             hBrush = ::CreateSolidBrush( GetSysColor( COLOR_WINDOW ) );
  3919.  
  3920.         RECT clientRect;
  3921.         GetClientRect(&clientRect);
  3922.         ::FrameRect( pdc.m_hDC, &clientRect, hBrush );     
  3923.         VERIFY(DeleteObject( hBrush ));
  3924.     }
  3925.  
  3926. }
  3927.  
  3928. BOOL COutlinerParent::OnEraseBkgnd( CDC * )
  3929. {
  3930.     return TRUE;
  3931. }
  3932.  
  3933. // Overloadable methods
  3934.  
  3935. BOOL COutlinerParent::ColumnCommand(int idCol)
  3936. {
  3937.     return FALSE;
  3938. }
  3939.  
  3940. BOOL COutlinerParent::RenderData(int idColumn, CRect & rect, CDC & dc, LPCTSTR lpsz )
  3941. {
  3942.     return FALSE;
  3943. }
  3944.  
  3945. //////////////////////////////////////////////////////////////////////////////
  3946. // COutlinerView
  3947.  
  3948. BEGIN_MESSAGE_MAP(COutlinerView,CView)
  3949.     ON_WM_CREATE()
  3950.     ON_WM_SIZE()
  3951.     ON_WM_SETFOCUS()
  3952. END_MESSAGE_MAP()
  3953.  
  3954. BOOL COutlinerView::PreCreateWindow(CREATESTRUCT& cs)
  3955. {
  3956.     cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
  3957.  
  3958.     return CView::PreCreateWindow(cs);
  3959. }
  3960.  
  3961. void COutlinerView::OnDraw ( CDC * pDC )
  3962. {
  3963. }
  3964.  
  3965. int COutlinerView::OnCreate ( LPCREATESTRUCT lpCreateStruct )
  3966. {
  3967.     int iRetVal = CView::OnCreate ( lpCreateStruct );
  3968.     LPCTSTR lpszClass = AfxRegisterWndClass( CS_VREDRAW, ::LoadCursor(NULL, IDC_ARROW));
  3969.     m_pOutlinerParent->Create( lpszClass, _T("NSOutlinerParent"), 
  3970.                                WS_VISIBLE|WS_CHILD|WS_CLIPCHILDREN,
  3971.                                CRect(0,0,0,0), this, 101 );
  3972.     return iRetVal;
  3973. }
  3974.  
  3975. void COutlinerView::OnSize ( UINT nType, int cx, int cy )
  3976. {
  3977.     CView::OnSize ( nType, cx, cy );
  3978.     m_pOutlinerParent->MoveWindow ( 0, 0, cx, cy, TRUE );
  3979. }
  3980.  
  3981. void COutlinerView::OnSetFocus ( CWnd * pOldWnd )
  3982. {
  3983.     CView::OnSetFocus ( pOldWnd );
  3984.     m_pOutlinerParent->SetFocus ( );
  3985. }
  3986.  
  3987.  
  3988.