WindowsXP-SP1/shell/ext/docpropv3/advanceddlg.cpp
2020-09-30 16:53:49 +02:00

1446 lines
32 KiB
C++

//
// Copyright 2001 - Microsoft Corporation
//
//
// Created By:
// Geoff Pease (GPease) 23-JAN-2001
//
// Maintained By:
// Geoff Pease (GPease) 23-JAN-2001
//
#include "pch.h"
#include "DocProp.h"
#include "DefProp.h"
#include "IEditVariantsInPlace.h"
#include "PropertyCacheItem.h"
#include "PropertyCache.h"
#include "AdvancedDlg.h"
#include "shutils.h"
#include "WMUser.h"
#include "IEditVariantsInPlace.h"
#include "EditTypeItem.h"
#pragma hdrstop
DEFINE_THISCLASS( "CAdvancedDlg" )
//
// This value is the offset of images in the bitmap representing the
// icons when multiple documents have been selected.
//
#define MULTIDOC_IMAGE_OFFSET_VALUE 2
// ************************************************************************
//
// Constructor / Destructor
//
// ************************************************************************
//
// Return Values:
// S_OK
// A new CAdvancedDlg was created successfully.
//
// E_OUTOFMEMORY
// Out of memory.
//
// other HRESULTs.
//
HRESULT
CAdvancedDlg::CreateInstance(
CAdvancedDlg ** pAdvDlgOut
, HWND hwndParentIn
)
{
TraceFunc( "" );
HRESULT hr;
Assert( pAdvDlgOut != NULL );
CAdvancedDlg * pthis = new CAdvancedDlg;
if ( pthis != NULL )
{
hr = THR( pthis->Init( hwndParentIn ) );
if ( SUCCEEDED( hr ) )
{
*pAdvDlgOut = pthis;
(*pAdvDlgOut)->AddRef( );
}
pthis->Release( );
}
else
{
hr = E_OUTOFMEMORY;
}
HRETURN( hr );
}
//
// Constructor
//
CAdvancedDlg::CAdvancedDlg( void )
: _cRef( 1 )
{
TraceFunc( "" );
Assert( 1 == _cRef );
Assert( NULL == _hwndParent );
Assert( NULL == _hdlg );
Assert( NULL == _hwndList );
Assert( NULL == _pEdit );
Assert( NULL == _pItem );
InterlockedIncrement( &g_cObjects );
TraceFuncExit();
}
//
// Description:
// Intializes the instance of the class. Put things that can
// fail into this method.
//
HRESULT
CAdvancedDlg::Init(
HWND hwndParentIn
)
{
TraceFunc( "" );
HRESULT hr = S_OK;
_hwndParent = hwndParentIn;
// IUnknown stuff
Assert( _cRef == 1 );
//
// Initialize the common controls
//
INITCOMMONCONTROLSEX iccx = { sizeof(INITCOMMONCONTROLSEX)
, ICC_LISTVIEW_CLASSES | ICC_USEREX_CLASSES | ICC_DATE_CLASSES
};
BOOL b = TBOOL( InitCommonControlsEx( &iccx ) );
if ( !b )
goto ErrorGLE;
//
// Create the dialog
//
_hdlg = CreateDialogParam( g_hInstance
, MAKEINTRESOURCE(IDD_ADVANCEDVIEW)
, _hwndParent
, DlgProc
, (LPARAM) this
);
if ( NULL == _hdlg )
goto ErrorGLE;
Cleanup:
HRETURN( hr );
ErrorGLE:
{
DWORD dwErr = TW32( GetLastError( ) );
hr = HRESULT_FROM_WIN32( dwErr );
}
goto Cleanup;
}
//
// Destructor
//
CAdvancedDlg::~CAdvancedDlg( )
{
TraceFunc( "" );
if ( NULL != _pEdit )
{
_pEdit->Release( );
}
if ( NULL != _hdlg )
{
DestroyWindow( _hdlg );
}
InterlockedDecrement( &g_cObjects );
TraceFuncExit();
}
// ************************************************************************
//
// IUnknown
//
// ************************************************************************
//
// QueryInterface
//
STDMETHODIMP
CAdvancedDlg::QueryInterface(
REFIID riid,
LPVOID *ppv
)
{
TraceQIFunc( riid, ppv );
HRESULT hr = E_NOINTERFACE;
if ( IsEqualIID( riid, __uuidof(IUnknown) ) )
{
*ppv = static_cast< IUnknown * >( this );
hr = S_OK;
}
#if 0
else if ( IsEqualIID( riid, __uuidof(IShellExtInit) ) )
{
*ppv = TraceInterface( __THISCLASS__, IShellExtInit, this, 0 );
hr = S_OK;
}
#endif
if ( SUCCEEDED( hr ) )
{
((IUnknown*) *ppv)->AddRef( );
}
QIRETURN( hr, riid );
}
//
// AddRef
//
STDMETHODIMP_(ULONG)
CAdvancedDlg::AddRef( void )
{
TraceFunc( "[IUnknown]" );
_cRef ++; // apartment
RETURN( _cRef );
}
//
// Release
//
STDMETHODIMP_(ULONG)
CAdvancedDlg::Release( void )
{
TraceFunc( "[IUnknown]" );
_cRef --; // apartment
if ( 0 != _cRef )
RETURN( _cRef );
delete this;
RETURN( 0 );
}
// ***************************************************************************
//
// Dialog Proc and Property Sheet Callback
//
// ***************************************************************************
//
// DlgProc
//
INT_PTR CALLBACK
CAdvancedDlg::DlgProc(
HWND hDlgIn
, UINT uMsgIn
, WPARAM wParam
, LPARAM lParam
)
{
// Don't do TraceFunc because every mouse movement will cause this function to be called.
WndMsg( hDlgIn, uMsgIn, wParam, lParam );
LRESULT lr = FALSE;
CAdvancedDlg * pPage = (CAdvancedDlg *) GetWindowLongPtr( hDlgIn, DWLP_USER );
if ( uMsgIn == WM_INITDIALOG )
{
SetWindowLongPtr( hDlgIn, DWLP_USER, lParam );
pPage = (CAdvancedDlg *) lParam ;
pPage->_hdlg = hDlgIn;
}
if ( pPage != NULL )
{
Assert( hDlgIn == pPage->_hdlg );
switch( uMsgIn )
{
case WM_INITDIALOG:
lr = pPage->OnInitDialog( );
break;
case WM_COMMAND:
lr = pPage->OnCommand( HIWORD(wParam), LOWORD(wParam), LPARAM(lParam) );
break;
case WM_NOTIFY:
lr = pPage->OnNotify( (int) wParam, (LPNMHDR) lParam );
break;
case WM_SETFOCUS:
lr = SendMessage( pPage->_hwndList, WM_SETFOCUS, wParam, lParam );
break;
case WM_DESTROY:
SetWindowLongPtr( hDlgIn, DWLP_USER, NULL );
lr = pPage->OnDestroy( );
break;
case WM_HELP:
lr = pPage->OnHelp( (LPHELPINFO) lParam );
break;
case WM_CONTEXTMENU:
lr = pPage->OnContextMenu( (HWND) wParam, LOWORD(lParam), HIWORD(lParam) );
break;
}
}
return lr;
}
//
// ListViewSubProc
//
LRESULT CALLBACK
CAdvancedDlg::ListViewSubclassProc(
HWND hwndIn
, UINT uMsgIn
, WPARAM wParam
, LPARAM lParam
, UINT_PTR uIdSubclassIn
, DWORD_PTR dwRefDataIn
)
{
// Don't do TraceFunc because every mouse movement will cause this function to be called.
WndMsg( hwndIn, uMsgIn, wParam, lParam );
LRESULT lr = FALSE;
CAdvancedDlg * pPage = (CAdvancedDlg *) dwRefDataIn;
Assert( NULL != pPage );
Assert( hwndIn == pPage->_hwndList );
Assert( IDC_PROPERTIES == uIdSubclassIn );
switch( uMsgIn )
{
case WM_COMMAND:
return pPage->List_OnCommand( LOWORD(wParam), HIWORD(wParam), lParam );
case WM_NOTIFY:
return pPage->List_OnNotify( (int) wParam, (LPNMHDR) lParam );
case WM_VSCROLL:
return pPage->List_OnVertScroll( LOWORD(wParam), HIWORD(wParam), (HWND) lParam );
case WM_HSCROLL:
return pPage->List_OnHornScroll( LOWORD(wParam), HIWORD(wParam), (HWND) lParam );
case WM_CHAR:
return pPage->List_OnChar( (UINT) wParam, lParam );
case WM_KEYDOWN:
return pPage->List_OnKeyDown( (UINT) wParam, lParam );
}
return DefSubclassProc( hwndIn, uMsgIn, wParam, lParam );
}
// ***************************************************************************
//
// Private methods
//
// ***************************************************************************
//
// WM_INITDIALOG handler
//
LRESULT
CAdvancedDlg::OnInitDialog( void )
{
TraceFunc( "" );
int iSize;
LVCOLUMN lvc;
TCHAR szTitle[ 64 ]; // random
ULONG idxFolder;
HIMAGELIST hil;
LRESULT lr = TRUE; // set the focus
Assert( NULL != _hdlg ); // this should have been initialized in the DlgProc.
_hwndList = GetDlgItem( _hdlg, IDC_PROPERTIES );
TBOOL( NULL != _hwndList );
//
// Enable ListView for Grouping mode.
//
SetWindowLongPtr( _hwndList, GWL_STYLE, GetWindowLongPtr( _hwndList, GWL_STYLE ) | LVS_AUTOARRANGE | LVS_SHOWSELALWAYS);
ListView_SetExtendedListViewStyle( _hwndList, LVS_EX_FULLROWSELECT );
ListView_EnableGroupView( _hwndList, TRUE );
//
// Add the image list
//
hil = ImageList_LoadImage( g_hInstance
, MAKEINTRESOURCE(IDB_TREE_IMAGELIST)
, 16
, 0
, RGB(255,0,255)
, IMAGE_BITMAP
, LR_SHARED
);
hil = ListView_SetImageList( _hwndList
, hil
, LVSIL_SMALL
);
Assert( NULL == hil ); // there shouldn't have been a previous image list.
//
// Setup up common values.
//
lvc.mask = LVCF_TEXT | LVCF_SUBITEM | LVCF_FMT;
lvc.fmt = LVCFMT_LEFT;
lvc.pszText = szTitle;
//
// Add Column 0
//
lvc.iSubItem = 0;
iSize = LoadString( g_hInstance, IDS_PROPERTY_HEADER_ITEM, szTitle, ARRAYSIZE(szTitle) );
AssertMsg( 0 != iSize, "Missing string resource?" );
ListView_InsertColumn( _hwndList, 0, &lvc );
//
// Add Column 1
//
lvc.iSubItem = 1;
iSize = LoadString( g_hInstance, IDS_VALUE_HEADER_ITEM, szTitle, ARRAYSIZE(szTitle) );
AssertMsg( 0 != iSize, "Missing string resource?" );
ListView_InsertColumn( _hwndList, 1, &lvc );
//
// Add the groups - In the end, if a group contains no items, the group
// header will not be shown.
//
for ( idxFolder = 0; NULL != g_rgTopLevelFolders[ idxFolder ].pPFID; idxFolder ++ )
{
//
// Add the property folder as a group item.
//
int iRet;
WCHAR szBuf[ 256 ]; // random
iRet = LoadString( g_hInstance, g_rgTopLevelFolders[ idxFolder ].nIDStringRes, szBuf, ARRAYSIZE(szBuf) );
AssertMsg( 0 != iRet, "Missing resource?" );
if ( 0 == iRet )
continue;
LVGROUP lvg;
lvg.cbSize = sizeof(LVGROUP);
lvg.mask = LVGF_HEADER | LVGF_GROUPID;
lvg.iGroupId = idxFolder;
lvg.pszHeader = szBuf;
LRESULT iItem = ListView_InsertGroup( _hwndList, -1, &lvg );
TBOOL( -1 != iItem );
}
//
// Subclass the listview
//
TBOOL( SetWindowSubclass( _hwndList, ListViewSubclassProc, IDC_PROPERTIES, (DWORD_PTR) this ) );
RETURN( lr );
}
//
// WM_COMMAND handler
//
LRESULT
CAdvancedDlg::OnCommand(
WORD wCodeIn
, WORD wCtlIn
, LPARAM lParam
)
{
TraceFunc( "" );
LRESULT lr = FALSE;
switch ( wCtlIn )
{
case IDC_SIMPLE:
if ( BN_CLICKED == wCodeIn )
{
THR( (HRESULT) SendMessage( _hwndParent, WMU_TOGGLE, 0, 0 ) );
}
break;
}
RETURN( lr );
}
//
// WM_NOTIFY handler
//
LRESULT
CAdvancedDlg::OnNotify(
int iCtlIdIn
, LPNMHDR pnmhIn
)
{
TraceFunc( "" );
LRESULT lr = FALSE;
switch( pnmhIn->code )
{
case NM_CLICK:
lr = OnNotifyClick( (LPNMITEMACTIVATE) pnmhIn );
break;
}
RETURN( lr );
}
//
// NM_CLICK handler
//
LRESULT
CAdvancedDlg::OnNotifyClick(
LPNMITEMACTIVATE pnmIn
)
{
TraceFunc( "" );
LRESULT lr = S_FALSE;
INT iItem;
Assert( NULL != pnmIn );
if ( -1 == pnmIn->iItem )
{
LVHITTESTINFO lvhti;
lvhti.pt = pnmIn->ptAction;
iItem = ListView_SubItemHitTest( _hwndList, &lvhti );
if ( -1 == iItem )
goto Cleanup;
if ( 1 != lvhti.iSubItem )
goto Cleanup;
}
else
{
if ( 1 != pnmIn->iSubItem )
goto Cleanup;
iItem = pnmIn->iItem;
}
STHR( CreateControlForProperty( iItem ) );
Cleanup:
RETURN( lr );
}
//
// WM_NOTIFY handler for the ListView Subclass
//
LRESULT
CAdvancedDlg::List_OnNotify(
int iCtlIdIn
, LPNMHDR pnmhIn
)
{
TraceFunc( "" );
LRESULT lr;
switch( pnmhIn->code )
{
case NM_KILLFOCUS:
if ( NULL != _pEdit )
{
STHR( PersistControlInProperty( ) );
_pEdit->Release( );
_pEdit = NULL;
}
break;
}
lr = DefSubclassProc( _hwndList, WM_NOTIFY, (WPARAM) iCtlIdIn, (LPARAM) pnmhIn );
RETURN( lr );
}
//
// WM_COMMAND handler for the ListView Subclass
//
LRESULT
CAdvancedDlg::List_OnCommand(
WORD wCtlIn
, WORD wCodeIn
, LPARAM lParam
)
{
TraceFunc( "" );
LRESULT lr = FALSE;
switch ( wCtlIn )
{
case IDC_INPLACEEDIT:
if ( EN_KILLFOCUS == wCodeIn || CBN_KILLFOCUS == wCodeIn )
{
if ( NULL != _pEdit )
{
STHR( PersistControlInProperty( ) );
_pEdit->Release( );
_pEdit = NULL;
}
}
break;
}
lr = DefSubclassProc( _hwndList, WM_COMMAND, MAKEWPARAM( wCtlIn, wCodeIn ), lParam );
RETURN( lr );
}
//
// WM_CHAR handler for ListView Subclass
//
LRESULT
CAdvancedDlg::List_OnChar(
UINT uKeyCodeIn
, LPARAM lParam
)
{
TraceFunc( "" );
HRESULT hr;
LRESULT lr = FALSE;
#if 0
SHORT sRepeatCount = ( lParam & 0xFFFF );
SHORT sScanCode = ( lParam & 0xF0000 ) >> 16;
BOOL fExtended = ( lParam & 0x100000 ) != 0;
BOOL fContext = ( lParam & 0x40000000 ) != 0;
BOOL fTransition = ( lParam & 0x80000000 ) != 0;
#endif
INT iItem = ListView_GetSelectionMark( _hwndList );
if ( -1 == iItem )
return DefSubclassProc( _hwndList, WM_KEYDOWN, uKeyCodeIn, lParam );
hr = STHR( CreateControlForProperty( iItem ) );
if ( S_OK == hr )
{
HWND hwnd = GetFocus( );
if ( _hwndList != hwnd )
{
lr = SendMessage( hwnd, WM_CHAR, (WPARAM) uKeyCodeIn, lParam );
}
}
RETURN( lr );
}
//
// WM_KEYDOWN handler for ListView Subclass
//
LRESULT
CAdvancedDlg::List_OnKeyDown(
UINT uKeyCodeIn
, LPARAM lParam
)
{
TraceFunc( "" );
LRESULT lr = FALSE;
#if 0
SHORT sRepeatCount = ( lParam & 0xFFFF );
SHORT sScanCode = ( lParam & 0xF0000 ) >> 16;
BOOL fExtended = ( lParam & 0x100000 ) != 0;
BOOL fContext = ( lParam & 0x40000000 ) != 0;
BOOL fTransition = ( lParam & 0x80000000 ) != 0;
#endif
switch ( uKeyCodeIn )
{
case VK_F2:
{
INT iItem = ListView_GetSelectionMark( _hwndList );
if ( -1 != iItem )
{
STHR( CreateControlForProperty( iItem ) );
}
}
// fall thru
default:
lr = DefSubclassProc( _hwndList, WM_KEYDOWN, (WPARAM) uKeyCodeIn, lParam );
break;
}
RETURN( lr );
}
//
// WM_VSCROLL handler
//
LRESULT
CAdvancedDlg::List_OnVertScroll(
WORD wCodeIn
, WORD wPosIn
, HWND hwndFromIn
)
{
TraceFunc( "" );
//
// Cancel any editting that's going on. This matches the behavior of
// DefView.
//
if ( NULL != _pEdit )
{
_pEdit->Release( );
_pEdit = NULL;
}
LRESULT lr = DefSubclassProc( _hwndList, WM_VSCROLL, MAKEWPARAM( wCodeIn, wPosIn ), (LPARAM) hwndFromIn );
RETURN( lr );
}
//
// WM_HCSCROLL handler
//
LRESULT
CAdvancedDlg::List_OnHornScroll(
WORD wCodeIn
, WORD wPosIn
, HWND hwndFromIn
)
{
TraceFunc( "" );
//
// Cancel any editting that's going on. This matches the behavior of
// DefView.
//
if ( NULL != _pEdit )
{
_pEdit->Release( );
_pEdit = NULL;
}
LRESULT lr = DefSubclassProc( _hwndList, WM_HSCROLL, MAKEWPARAM( wCodeIn, wPosIn ), (LPARAM) hwndFromIn );
RETURN( lr );
}
//
// WM_DESTROY handler
//
LRESULT
CAdvancedDlg::OnDestroy( void )
{
TraceFunc( "" );
LRESULT lr = FALSE;
RETURN( lr );
}
//
// Description:
// Creates and initializes the control to edit the property selected.
//
// Return Values:
// S_OK
// Successfully created and initialized control.
//
// S_FALSE
// Read-only property - no control created.
//
// E_FAIL
// Failed to create control.
//
// other HRESULTs
//
HRESULT
CAdvancedDlg::CreateControlForProperty(
INT iItemIn
)
{
TraceFunc( "" );
HRESULT hr;
BOOL bRet;
CLSID clsidControl;
RECT rectItem;
RECT rectList;
UINT uCodePage;
LVITEM lvi;
DEFVAL * pDefVals;
int iImage;
PROPVARIANT * ppropvar;
IPropertyUI * ppui = NULL;
lvi.iItem = iItemIn;
lvi.mask = LVIF_PARAM;
lvi.iSubItem = 0;
bRet = TBOOL( ListView_GetItem( _hwndList, &lvi ) );
if ( !bRet )
goto ControlFailed;
_pItem = (CPropertyCacheItem *) lvi.lParam;
AssertMsg( NULL != _pItem, "Programming error - how did this item get added?" );
hr = THR( _pItem->GetImageIndex( &iImage ) );
if ( S_OK != hr )
goto Cleanup;
//
// Don't invoke the "Edit control" if the property is read-only.
//
if ( PTI_PROP_READONLY == iImage )
{
hr = S_FALSE;
goto Cleanup;
}
hr = STHR( _pItem->GetControlCLSID( &clsidControl ) );
if ( S_OK != hr )
goto Cleanup;
hr = THR( _pItem->GetCodePage( &uCodePage ) );
if ( FAILED( hr ) )
goto Cleanup;
hr = STHR( _pItem->GetPropertyUIHelper( &ppui ) );
if ( S_OK != hr )
goto Cleanup;
hr = THR( _pItem->GetPropertyValue( &ppropvar ) );
if ( FAILED( hr ) )
goto Cleanup;
hr = STHR( _pItem->GetStateStrings( &pDefVals ) );
if ( FAILED( hr ) )
goto Cleanup;
Assert( NULL == _pEdit );
hr = THR( CoCreateInstance( clsidControl, NULL, CLSCTX_INPROC, TYPESAFEPARAMS(_pEdit) ) );
if ( FAILED( hr ) )
goto Cleanup;
bRet = TBOOL( ListView_GetSubItemRect( _hwndList, lvi.iItem, 1, LVIR_BOUNDS , &rectItem) );
if ( !bRet )
goto ControlFailed;
//
// Make sure the rect is only in the visible region of the list view.
//
bRet = TBOOL( GetWindowRect( _hwndList, &rectList ) );
if ( !bRet )
goto ControlFailed;
if ( rectItem.right > rectList.right - rectList.left )
{
rectItem.right = rectList.right - rectList.left;
}
if ( rectItem.left < 0 )
{
rectItem.left = 0;
}
hr = THR( _pEdit->Initialize( _hwndList, uCodePage, &rectItem, ppui, ppropvar, pDefVals ) );
if ( FAILED( hr ) )
goto Cleanup;
Cleanup:
if ( NULL != ppui )
{
ppui->Release( );
}
HRETURN( hr );
ControlFailed:
hr = THR( E_FAIL );
goto Cleanup;
}
//
// Description:
// Informs the control, _pEdit, to persist its value into the variant.
//
// Return Value:
// S_OK
// Success! Property value updated.
//
// S_FALSE
// _pEdit was NULL.
//
// other HRESULTs.
//
HRESULT
CAdvancedDlg::PersistControlInProperty( void )
{
TraceFunc( "" );
HRESULT hr;
LVITEM lvi;
LVFINDINFO lvfi;
VARTYPE vt;
PROPVARIANT * ppropvar;
if ( NULL == _pEdit )
goto NoEditControlEditting;
lvfi.flags = LVFI_PARAM;
lvfi.lParam = (LPARAM) _pItem;
lvfi.vkDirection = VK_DOWN;
lvi.iItem = ListView_FindItem( _hwndList, -1, &lvfi );
if ( -1 == lvi.iItem )
goto NoEditControlEditting;
hr = THR( _pItem->GetPropertyValue( &ppropvar ) );
if ( FAILED( hr ) )
goto Cleanup;
switch( ppropvar->vt )
{
case VT_EMPTY:
case VT_NULL:
{
hr = THR( _pItem->GetDefaultVarType( &vt ) );
if ( FAILED( hr ) )
goto Cleanup;
}
break;
default:
vt = ppropvar->vt;
break;
}
PropVariantInit( ppropvar );
hr = STHR( _pEdit->Persist( vt, ppropvar ) );
if ( FAILED( hr ) )
goto Cleanup;
if ( S_OK == hr )
{
hr = THR( _pItem->MarkDirty( ) );
if ( FAILED( hr ) )
goto Cleanup;
hr = THR( _pItem->GetPropertyStringValue( (LPCWSTR *) &lvi.pszText ) );
if ( FAILED( hr ) )
goto Cleanup;
lvi.mask = LVIF_TEXT;
lvi.iSubItem = 1;
BOOL bRet = TBOOL( ListView_SetItem( _hwndList, &lvi ) );
if ( !bRet )
goto NoEditControlEditting;
//
// Tell the property sheet to activate the "Apply" button.
//
PropSheet_Changed( GetParent( _hwndParent ), _hwndParent );
}
Cleanup:
HRETURN( hr );
NoEditControlEditting:
hr = THR( S_FALSE );
goto Cleanup;
}
//
// WM_HELP handler
//
LRESULT
CAdvancedDlg::OnHelp(
LPHELPINFO pHelpInfoIn
)
{
TraceFunc( "" );
LRESULT lr = FALSE;
THR( DoHelp( (HWND) pHelpInfoIn->hItemHandle, pHelpInfoIn->MousePos.x, pHelpInfoIn->MousePos.y, HELP_WM_HELP ) );
RETURN( lr );
}
//
// WM_CONTEXTMENU handler
//
LRESULT
CAdvancedDlg::OnContextMenu(
HWND hwndIn
, int iXIn
, int iYIn
)
{
TraceFunc( "" );
LRESULT lr = FALSE;
THR( DoHelp( hwndIn, iXIn, iYIn, HELP_CONTEXTMENU ) );
RETURN( lr );
}
//
// Description:
// Handles locating the item within the list view and construct
// a fake IDC to IDH to display the correct help text for the
// item.
//
// Return Values:
// S_OK
// Success.
//
HRESULT
CAdvancedDlg::DoHelp(
HWND hwndIn
, int iXIn
, int iYIn
, UINT uCommandIn
)
{
TraceFunc( "" );
HRESULT hr = S_OK;
HWND hwndList = GetDlgItem( _hdlg, IDC_PROPERTIES );
if ( hwndList == hwndIn )
{
BOOL bRet;
HRESULT hr;
int iItem;
RECT rcList;
LVITEM lvi;
LPCWSTR pszHelpFile; // don't free
UINT uHelpId;
CPropertyCacheItem * pItem;
LVHITTESTINFO lvhti;
DWORD mapIDStoIDH[ ] = { IDC_PROPERTIES, 0, 0, 0 };
bRet = TBOOL( GetWindowRect( hwndList, &rcList ) );
if ( !bRet )
goto Cleanup;
lvhti.pt.x = iXIn - rcList.left;
lvhti.pt.y = iYIn - rcList.top;
lvhti.flags = LVHT_ONITEMICON | LVHT_ONITEMLABEL | LVHT_ONITEMSTATEICON;
iItem = ListView_HitTest( hwndList, &lvhti );
if ( -1 == iItem )
goto Cleanup; // item not found.
lvi.iItem = iItem;
lvi.mask = LVIF_PARAM;
lvi.iSubItem = 0;
bRet = TBOOL( ListView_GetItem( _hwndList, &lvi ) );
if ( !bRet )
goto Cleanup;
pItem = (CPropertyCacheItem *) lvi.lParam;
AssertMsg( NULL != pItem, "Programming error - how did this item get added?" );
hr = THR( pItem->GetPropertyHelpInfo( &pszHelpFile, &uHelpId ) );
if ( FAILED( hr ) )
goto Cleanup;
mapIDStoIDH[ 1 ] = uHelpId;
TBOOL( WinHelp( hwndIn, pszHelpFile, uCommandIn, (DWORD_PTR)(LPSTR) mapIDStoIDH ) );
}
Cleanup:
HRETURN( hr );
}
// ***************************************************************************
//
// Public methods
//
// ***************************************************************************
//
// Description:
// Hides the dialog.
//
// Return Value:
// S_OK
// Success!
//
HRESULT
CAdvancedDlg::Hide( void )
{
TraceFunc( "" );
HRESULT hr;
ShowWindow( _hdlg, SW_HIDE );
hr = S_OK;
HRETURN( hr );
}
//
// Description:
// Shows the dialog.
//
// Return Values:
// S_OK
// Success!
//
HRESULT
CAdvancedDlg::Show( void )
{
TraceFunc( "" );
HRESULT hr = S_OK;
ShowWindow( _hdlg, SW_SHOW );
SetFocus( _hdlg );
HRETURN( hr );
}
//
// Description:
// Populates the properties of the dialog.
//
// Return Values:
// S_OK
// Success!
//
// E_INVALIDARG
// ppcIn is NULL.
//
// other HRESULTs.
//
HRESULT
CAdvancedDlg::PopulateProperties(
CPropertyCache * ppcIn
, DWORD dwDocTypeIn
, BOOL fMultipleIn
)
{
TraceFunc( "" );
HRESULT hr;
RECT rect;
LVCOLUMN lvc;
BOOL bRet;
LVITEM lvi;
ULONG idxFolder;
ULONG idxProperty;
CPropertyCacheItem * pItem;
int iItem = 0;
//
// Check parameters
//
if ( NULL == ppcIn )
{
ReplaceListViewWithString( IDS_NOPROPERTIES_CAPTION );
hr = S_OK;
goto Cleanup;
}
_fMultipleSources = fMultipleIn;
//
// Clear out the previous list view contents.
//
TBOOL( ListView_DeleteAllItems( _hwndList ) );
//
// See if we have any properties to show.
//
hr = STHR( ppcIn->GetNextItem( NULL, &pItem ) );
if ( S_OK == hr )
{
//
// Walk the default property list and add items that match this property
// folder to listview.
//
// If the SHIFT key is down, all properties retrieved and added will be
// shown (if possible).
//
for ( idxProperty = 0; NULL != g_rgDefPropertyItems[ idxProperty ].pszName; idxProperty ++ )
{
if ( !( g_rgDefPropertyItems[ idxProperty ].dwSrcType & dwDocTypeIn )
&& !( GetKeyState( VK_SHIFT ) < 0 )
)
{
continue; // property doesn't apply
}
//
// Search the property cache for the entry.
//
hr = STHR( ppcIn->FindItemEntry( g_rgDefPropertyItems[ idxProperty ].pFmtID
, g_rgDefPropertyItems[ idxProperty ].propID
, &pItem
) );
if ( S_OK != hr )
continue; // property not found... skip it
Assert ( NULL != pItem ); // paranoid
//
// Find the group that the property belongs too.
//
for ( idxFolder = 0; NULL != g_rgTopLevelFolders[ idxFolder ].pPFID; idxFolder ++ )
{
if ( *g_rgDefPropertyItems[ idxProperty ].ppfid == *g_rgTopLevelFolders[ idxFolder ].pPFID )
{
break;
}
}
AssertMsg( NULL != g_rgTopLevelFolders[ idxFolder ].pPFID, "Missing folder for listed property. Check DOCPROP.CPP." );
//
// Add the property name below the group
//
lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE | LVIF_GROUPID;
lvi.iSubItem = 0;
lvi.iItem = iItem;
lvi.iGroupId = idxFolder;
lvi.lParam = (LPARAM) pItem;
hr = THR( pItem->GetImageIndex( &lvi.iImage ) );
if ( FAILED( hr ) )
{
lvi.iImage = 0;
}
else
{
if ( _fMultipleSources )
{
lvi.iImage += MULTIDOC_IMAGE_OFFSET_VALUE;
}
}
hr = THR( pItem->GetPropertyTitle( (LPCWSTR *) &lvi.pszText ) );
if ( FAILED( hr ) )
continue;
iItem = ListView_InsertItem( _hwndList, &lvi );
if ( -1 == iItem )
continue;
//
// Now add the property value.
//
lvi.mask = LVIF_TEXT;
lvi.iItem = iItem;
lvi.iSubItem = 1;
hr = THR( pItem->GetPropertyStringValue( (LPCWSTR *) &lvi.pszText ) );
if ( FAILED( hr ) )
continue;
bRet = TBOOL( ListView_SetItem( _hwndList, &lvi ) );
if ( !bRet )
continue;
iItem ++;
}
//
// Give the first item focus
//
ListView_SetItemState( _hwndList, 0, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED );
}
if ( 0 == iItem )
{
if ( _fMultipleSources )
{
ReplaceListViewWithString( IDS_NOCOMMONS_CAPTION );
}
else
{
ReplaceListViewWithString( IDS_NOPROPERTIES_CAPTION );
}
}
//
// Auto-adjust the column widths making sure that the first column doesn't
// make itself too big.
//
TBOOL( ListView_SetColumnWidth( _hwndList, 0, LVSCW_AUTOSIZE_USEHEADER ) );
bRet = TBOOL( GetClientRect( _hwndList, &rect ) );
if ( bRet )
{
lvc.mask = LVCF_WIDTH;
bRet = TBOOL( ListView_GetColumn( _hwndList, 0, &lvc ) );
if ( bRet )
{
int iSize = rect.right / 2;
if ( lvc.cx > iSize )
{
TBOOL( ListView_SetColumnWidth( _hwndList, 0, iSize ) );
TBOOL( ListView_SetColumnWidth( _hwndList, 1, iSize ) );
}
else
{
TBOOL( ListView_SetColumnWidth( _hwndList, 1, rect.right - lvc.cx ) );
}
}
}
if ( !bRet )
{
TBOOL( ListView_SetColumnWidth( _hwndList, 1, LVSCW_AUTOSIZE_USEHEADER ) );
}
hr = S_OK;
Cleanup:
HRETURN( hr );
}
//
// Description:
// Hides the list view control and displays a STATIC window with
// the text found in the string resource idsIn.
//
void
CAdvancedDlg::ReplaceListViewWithString( int idsIn )
{
TraceFunc( "" );
int iRet;
RECT rc;
WCHAR szCaption[ 255 ]; // random
iRet = LoadString( g_hInstance, idsIn, szCaption, ARRAYSIZE(szCaption) );
AssertMsg( iRet, "Missing string resource?" );
ShowWindow( _hwndList, SW_HIDE );
TBOOL( GetWindowRect( _hwndList, &rc ) );
iRet = MapWindowRect( HWND_DESKTOP, _hdlg, &rc );
TBOOL( 0 != iRet );
HWND hwnd = CreateWindow( WC_STATIC
, szCaption
, WS_CHILD | WS_VISIBLE
, rc.left
, rc.top
, rc.right - rc.left
, rc.bottom - rc.top
, _hdlg
, (HMENU) -1
, g_hInstance
, NULL
);
TBOOL( NULL != hwnd );
HFONT hFont = (HFONT) SendMessage( _hdlg, WM_GETFONT, 0, 0 );
SendMessage( hwnd, WM_SETFONT, (WPARAM) hFont, 0 );
TraceFuncExit( );
}