984 lines
25 KiB
C++
984 lines
25 KiB
C++
|
#include "shellprv.h"
|
||
|
#include "defviewp.h"
|
||
|
#include "duiview.h"
|
||
|
#include "duitask.h"
|
||
|
#include "dvtasks.h"
|
||
|
#include "contextmenu.h"
|
||
|
#include "ids.h"
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
// Returns a given task element's root HWND element.
|
||
|
//
|
||
|
//
|
||
|
|
||
|
HRESULT GetElementRootHWNDElement(Element *pe, HWNDElement **pphwndeRoot)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
if (pe)
|
||
|
{
|
||
|
Element *peRoot = pe->GetRoot();
|
||
|
if (peRoot && peRoot->GetClassInfo()->IsSubclassOf(HWNDElement::Class))
|
||
|
{
|
||
|
*pphwndeRoot = reinterpret_cast<HWNDElement *>(peRoot);
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*pphwndeRoot = NULL;
|
||
|
hr = E_FAIL;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_INVALIDARG;
|
||
|
ASSERT(FALSE);
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// Returns a given task element's root HWND element's HWND.
|
||
|
//
|
||
|
//
|
||
|
|
||
|
HRESULT GetElementRootHWND(Element *pe, HWND *phwnd)
|
||
|
{
|
||
|
HWNDElement *phwndeRoot;
|
||
|
HRESULT hr = GetElementRootHWNDElement(pe, &phwndeRoot);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
*phwnd = phwndeRoot->GetHWND();
|
||
|
hr = *phwnd ? S_OK : S_FALSE;
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// Creates an instance of the ActionTask and
|
||
|
// initializes it
|
||
|
//
|
||
|
// nActive - Activation type
|
||
|
// puiCommand - the Task itself
|
||
|
// ppElement - Receives element pointer
|
||
|
|
||
|
HRESULT ActionTask::Create(UINT nActive, IUICommand* puiCommand, IShellItemArray* psiItemArray, CDUIView* pDUIView, CDefView* pDefView, OUT Element** ppElement)
|
||
|
{
|
||
|
*ppElement = NULL;
|
||
|
|
||
|
if (!puiCommand || !pDUIView || !pDefView)
|
||
|
{
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
ActionTask* pAT = HNewAndZero<ActionTask>();
|
||
|
if (!pAT)
|
||
|
{
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
HRESULT hr = pAT->Initialize(puiCommand, psiItemArray, pDUIView, pDefView);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
pAT->Destroy();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
*ppElement = pAT;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
// Initializes this task
|
||
|
//
|
||
|
// puiCommand - the Task itself
|
||
|
|
||
|
HRESULT ActionTask::Initialize(IUICommand *puiCommand, IShellItemArray *psiItemArray, CDUIView *pDUIView, CDefView *pDefView)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
// Initialize this DUI Element.
|
||
|
hr = InitializeElement();
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// Initialize the contained DUI Button.
|
||
|
hr = InitializeButton();
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// Save the pointer to the IUICommand class
|
||
|
puiCommand->AddRef();
|
||
|
_puiCommand = puiCommand;
|
||
|
|
||
|
// Save the pointer to the CDUIView class
|
||
|
pDUIView->AddRef();
|
||
|
_pDUIView = pDUIView;
|
||
|
|
||
|
// Save the pointer to the CDefView class
|
||
|
pDefView->AddRef();
|
||
|
_pDefView = pDefView;
|
||
|
|
||
|
// Save the pointer to the IShellItemArray class (if available)
|
||
|
if (psiItemArray)
|
||
|
{
|
||
|
psiItemArray->AddRef();
|
||
|
_psiItemArray = psiItemArray;
|
||
|
}
|
||
|
|
||
|
UpdateTaskUI();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT ActionTask::InitializeElement()
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
// Initialize base class (normal display node creation).
|
||
|
hr = Element::Initialize(0);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// Create a layout for this element.
|
||
|
Value *pv;
|
||
|
hr = BorderLayout::Create(0, NULL, &pv);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// Set the layout for this element.
|
||
|
hr = SetValue(LayoutProp, PI_Local, pv);
|
||
|
pv->Release();
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceMsg(TF_ERROR, "ActionTask::Initialize: base class failed to initialize with 0x%x", hr);
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT ActionTask::InitializeButton()
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
// Create the button.
|
||
|
hr = Button::Create((Element**)&_peButton);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// Set some button attributes.
|
||
|
_peButton->SetLayoutPos(BLP_Left);
|
||
|
_peButton->SetAccessible(true);
|
||
|
_peButton->SetAccRole(ROLE_SYSTEM_PUSHBUTTON);
|
||
|
TCHAR szDefaultAction[50] = {0};
|
||
|
LoadString(HINST_THISDLL, IDS_LINKWINDOW_DEFAULTACTION, szDefaultAction, ARRAYSIZE(szDefaultAction));
|
||
|
_peButton->SetAccDefAction(szDefaultAction);
|
||
|
|
||
|
// Create a border layout for the icon and title in the button.
|
||
|
Value *pv;
|
||
|
hr = BorderLayout::Create(0, NULL, &pv);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// Set the button layout.
|
||
|
hr = _peButton->SetValue(LayoutProp, PI_Local, pv);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// Add the button to this element.
|
||
|
hr = Add(_peButton);
|
||
|
}
|
||
|
pv->Release();
|
||
|
}
|
||
|
|
||
|
// Cleanup (if necessary).
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
_peButton->Destroy();
|
||
|
_peButton = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
ActionTask::ActionTask()
|
||
|
{
|
||
|
// Catch unexpected STACK allocations which would break us.
|
||
|
ASSERT(_peButton == NULL);
|
||
|
ASSERT(_puiCommand == NULL);
|
||
|
ASSERT(_psiItemArray == NULL);
|
||
|
ASSERT(_pDefView == NULL);
|
||
|
ASSERT(_pDefView == NULL);
|
||
|
ASSERT(_hwndRoot == NULL);
|
||
|
ASSERT(_pDUIView == NULL);
|
||
|
|
||
|
_bInfotip = FALSE;
|
||
|
}
|
||
|
|
||
|
ActionTask::~ActionTask()
|
||
|
{
|
||
|
if (_bInfotip)
|
||
|
{
|
||
|
// Destroy the infotip.
|
||
|
_pDefView->DestroyInfotip(_hwndRoot, (UINT_PTR)this);
|
||
|
}
|
||
|
|
||
|
if (_puiCommand)
|
||
|
_puiCommand->Release();
|
||
|
|
||
|
if (_psiItemArray)
|
||
|
_psiItemArray->Release();
|
||
|
|
||
|
if (_pDUIView)
|
||
|
_pDUIView->Release();
|
||
|
|
||
|
if (_pDefView)
|
||
|
_pDefView->Release();
|
||
|
}
|
||
|
|
||
|
void ActionTask::UpdateTaskUI()
|
||
|
{
|
||
|
// Set the icon
|
||
|
|
||
|
LPWSTR pIconDesc;
|
||
|
if (SUCCEEDED(_puiCommand->get_Icon(_psiItemArray, &pIconDesc)))
|
||
|
{
|
||
|
Element* pe;
|
||
|
if (SUCCEEDED(Element::Create(0, &pe)))
|
||
|
{
|
||
|
pe->SetLayoutPos(BLP_Left);
|
||
|
pe->SetID(L"icon");
|
||
|
_peButton->Add(pe);
|
||
|
|
||
|
HICON hIcon = DUILoadIcon(pIconDesc, TRUE);
|
||
|
if (hIcon)
|
||
|
{
|
||
|
Value* pv = Value::CreateGraphic (hIcon);
|
||
|
if (pv)
|
||
|
{
|
||
|
pe->SetValue(Element::ContentProp, PI_Local, pv);
|
||
|
pv->Release();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DestroyIcon(hIcon);
|
||
|
|
||
|
TraceMsg(TF_ERROR, "ActionTask::Initialize: CreateGraphic for the icon failed.");
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceMsg(TF_ERROR, "ActionTask::Initialize: DUILoadIcon failed.");
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceMsg(TF_ERROR, "ActionTask::Initialize: Failed to create icon element");
|
||
|
}
|
||
|
|
||
|
CoTaskMemFree(pIconDesc);
|
||
|
}
|
||
|
|
||
|
// Set the title
|
||
|
|
||
|
LPWSTR pszTitleDesc;
|
||
|
if (SUCCEEDED(_puiCommand->get_Name(_psiItemArray, &pszTitleDesc)))
|
||
|
{
|
||
|
Element* pe;
|
||
|
if (SUCCEEDED(Element::Create(0, &pe)))
|
||
|
{
|
||
|
pe->SetLayoutPos(BLP_Left);
|
||
|
pe->SetID(L"title");
|
||
|
_peButton->Add(pe);
|
||
|
|
||
|
Value* pv = Value::CreateString(pszTitleDesc);
|
||
|
if (pv)
|
||
|
{
|
||
|
_peButton->SetValue(Element::AccNameProp, PI_Local, pv);
|
||
|
pe->SetValue(Element::ContentProp, PI_Local, pv);
|
||
|
pv->Release();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceMsg(TF_ERROR, "ActionTask::Initialize: CreateString for the title failed.");
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceMsg(TF_ERROR, "ActionTask::Initialize: Failed to create title element");
|
||
|
}
|
||
|
|
||
|
CoTaskMemFree(pszTitleDesc);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Shows/hides an Infotip window
|
||
|
//
|
||
|
// bShow - TRUE or FALSE to show or hide the Infotip window
|
||
|
|
||
|
HRESULT ActionTask::ShowInfotipWindow(BOOL bShow)
|
||
|
{
|
||
|
RECT rect = { 0 };
|
||
|
HRESULT hr;
|
||
|
|
||
|
if (bShow)
|
||
|
{
|
||
|
_pDUIView->CalculateInfotipRect(this, &rect);
|
||
|
if (_bInfotip)
|
||
|
{
|
||
|
// Reposition infotip at position.
|
||
|
hr = _pDefView->RepositionInfotip(_hwndRoot, (UINT_PTR)this, &rect);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Create infotip at position (on the ui thread).
|
||
|
LPWSTR pwszInfotip;
|
||
|
hr = _puiCommand->get_Tooltip(_psiItemArray, &pwszInfotip);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = GetElementRootHWND(this, &_hwndRoot);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = _pDefView->CreateInfotip(_hwndRoot, (UINT_PTR)this, &rect, pwszInfotip, 0);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
_bInfotip = TRUE;
|
||
|
}
|
||
|
}
|
||
|
CoTaskMemFree(pwszInfotip);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (_bInfotip)
|
||
|
{
|
||
|
// Reposition infotip at nowhere.
|
||
|
hr = _pDefView->RepositionInfotip(_hwndRoot, (UINT_PTR)this, &rect);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// No infotip == no show!
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// System event handler
|
||
|
//
|
||
|
//
|
||
|
|
||
|
void ActionTask::OnPropertyChanged(PropertyInfo* ppi, int iIndex, Value* pvOld, Value* pvNew)
|
||
|
{
|
||
|
// Default processing...
|
||
|
Element::OnPropertyChanged(ppi, iIndex, pvOld, pvNew);
|
||
|
|
||
|
// Extended processing for infotip...
|
||
|
if (IsProp(MouseWithin))
|
||
|
ShowInfotipWindow(pvNew->GetBool() && SHShowInfotips());
|
||
|
}
|
||
|
|
||
|
|
||
|
// Event handler
|
||
|
//
|
||
|
// pev - event information
|
||
|
|
||
|
void ActionTask::OnEvent(Event* pev)
|
||
|
{
|
||
|
if (pev->peTarget == _peButton)
|
||
|
{
|
||
|
if (pev->uidType == Button::Click)
|
||
|
{
|
||
|
if ( NULL != _pDUIView ) // This should have been past in during initialization.
|
||
|
{
|
||
|
_pDUIView->DelayedNavigation(_psiItemArray, _puiCommand);
|
||
|
}
|
||
|
pev->fHandled = true;
|
||
|
}
|
||
|
}
|
||
|
Element::OnEvent(pev);
|
||
|
}
|
||
|
|
||
|
// Class information
|
||
|
|
||
|
IClassInfo* ActionTask::Class = NULL;
|
||
|
HRESULT ActionTask::Register()
|
||
|
{
|
||
|
return ClassInfo<ActionTask,Element>::Register(L"ActionTask", NULL, 0);
|
||
|
}
|
||
|
|
||
|
|
||
|
// Creates an instance of the DestinationTask and
|
||
|
// initializes it
|
||
|
//
|
||
|
// nActive - Activation type
|
||
|
// pidl - pidl of destination
|
||
|
// ppElement - Receives element pointer
|
||
|
//
|
||
|
|
||
|
HRESULT DestinationTask::Create(UINT nActive, LPITEMIDLIST pidl,
|
||
|
CDUIView * pDUIView, CDefView *pDefView, OUT Element** ppElement)
|
||
|
{
|
||
|
*ppElement = NULL;
|
||
|
|
||
|
if (!pidl || !pDUIView || !pDefView)
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
DestinationTask* pDT = HNewAndZero<DestinationTask>();
|
||
|
if (!pDT)
|
||
|
{
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
HRESULT hr = pDT->Initialize(pidl, pDUIView, pDefView);
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
pDT->Destroy();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
*ppElement = pDT;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
// Initializes this task
|
||
|
//
|
||
|
// pidl - Destination pidl
|
||
|
|
||
|
HRESULT DestinationTask::Initialize(LPITEMIDLIST pidl, CDUIView *pDUIView, CDefView *pDefView)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
// Initialize this DUI Element.
|
||
|
hr = InitializeElement();
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
HICON hIcon = NULL;
|
||
|
WCHAR szTitle[MAX_PATH];
|
||
|
|
||
|
// Retrieve the info needed to initialize the contained DUI Button.
|
||
|
HIMAGELIST himl;
|
||
|
if (Shell_GetImageLists(NULL, &himl))
|
||
|
{
|
||
|
IShellFolder *psf;
|
||
|
LPCITEMIDLIST pidlItem;
|
||
|
hr = SHBindToFolderIDListParent(NULL, pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlItem);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// Retrieve icon.
|
||
|
int iSysIndex = SHMapPIDLToSystemImageListIndex(psf, pidlItem, NULL);
|
||
|
if (iSysIndex != -1)
|
||
|
{
|
||
|
hIcon = ImageList_GetIcon(himl, iSysIndex, 0);
|
||
|
}
|
||
|
|
||
|
// Retrieve text.
|
||
|
hr = DisplayNameOf(psf, pidlItem, SHGDN_INFOLDER, szTitle, ARRAYSIZE(szTitle));
|
||
|
|
||
|
psf->Release();
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_FAIL;
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// Initialize the contained DUI Button.
|
||
|
hr = InitializeButton(hIcon, szTitle);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// Save the destination pidl
|
||
|
hr = SHILClone(pidl, &_pidlDestination);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// Save the pointer to the CDUIView class
|
||
|
pDUIView->AddRef();
|
||
|
_pDUIView = pDUIView;
|
||
|
|
||
|
// Save the pointer to the CDefView class
|
||
|
pDefView->AddRef();
|
||
|
_pDefView = pDefView;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT DestinationTask::InitializeElement()
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
// Initialize base class (normal display node creation).
|
||
|
hr = Element::Initialize(0);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// Create a layout for this element.
|
||
|
Value *pv;
|
||
|
hr = BorderLayout::Create(0, NULL, &pv);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// Set the layout for this element.
|
||
|
hr = SetValue(LayoutProp, PI_Local, pv);
|
||
|
pv->Release();
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceMsg(TF_ERROR, "DestinationTask::Initialize: base class failed to initialize with 0x%x", hr);
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT DestinationTask::InitializeButton(HICON hIcon, LPCWSTR pwszTitle)
|
||
|
{
|
||
|
ASSERT(pwszTitle);
|
||
|
HRESULT hr;
|
||
|
|
||
|
// Create the button.
|
||
|
hr = Button::Create((Element**)&_peButton);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// Set some button attributes.
|
||
|
_peButton->SetLayoutPos(BLP_Left);
|
||
|
_peButton->SetAccessible(true);
|
||
|
_peButton->SetAccRole(ROLE_SYSTEM_LINK);
|
||
|
TCHAR szDefaultAction[50] = {0};
|
||
|
LoadString(HINST_THISDLL, IDS_LINKWINDOW_DEFAULTACTION, szDefaultAction, ARRAYSIZE(szDefaultAction));
|
||
|
_peButton->SetAccDefAction(szDefaultAction);
|
||
|
|
||
|
// Create a border layout for the icon and title in the button.
|
||
|
Value *pv;
|
||
|
hr = BorderLayout::Create(0, NULL, &pv);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// Set the layout for the button.
|
||
|
hr = _peButton->SetValue(LayoutProp, PI_Local, pv);
|
||
|
pv->Release();
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
HRESULT hr2 = E_FAIL;
|
||
|
HRESULT hr3 = E_FAIL;
|
||
|
|
||
|
// Init the button icon.
|
||
|
if (hIcon)
|
||
|
{
|
||
|
Element *peIcon;
|
||
|
|
||
|
// Create an icon element.
|
||
|
hr2 = Element::Create(0, &peIcon);
|
||
|
if (SUCCEEDED(hr2))
|
||
|
{
|
||
|
// Set some icon element attributes.
|
||
|
peIcon->SetLayoutPos(BLP_Left);
|
||
|
peIcon->SetID(L"icon");
|
||
|
|
||
|
// Add the icon to the icon element.
|
||
|
pv = Value::CreateGraphic(hIcon);
|
||
|
if (pv)
|
||
|
{
|
||
|
hr2 = peIcon->SetValue(Element::ContentProp, PI_Local, pv);
|
||
|
pv->Release();
|
||
|
if (SUCCEEDED(hr2))
|
||
|
{
|
||
|
// Add the icon element to the button.
|
||
|
hr2 = _peButton->Add(peIcon);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Cleanup (if necessary).
|
||
|
if (FAILED(hr2))
|
||
|
{
|
||
|
peIcon->Destroy();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Init the button title.
|
||
|
if (pwszTitle[0])
|
||
|
{
|
||
|
Element *peTitle;
|
||
|
|
||
|
// Create a title element.
|
||
|
hr3 = Element::Create(0, &peTitle);
|
||
|
if (SUCCEEDED(hr3))
|
||
|
{
|
||
|
// Set some title element attributes.
|
||
|
peTitle->SetLayoutPos(BLP_Left);
|
||
|
peTitle->SetID(L"title");
|
||
|
|
||
|
// Add the title to the title element.
|
||
|
pv = Value::CreateString(pwszTitle);
|
||
|
if (pv)
|
||
|
{
|
||
|
hr3 = peTitle->SetValue(Element::ContentProp, PI_Local, pv);
|
||
|
if (SUCCEEDED(hr3))
|
||
|
{
|
||
|
_peButton->SetValue(Element::AccNameProp, PI_Local, pv);
|
||
|
|
||
|
// Add the title element to the button.
|
||
|
hr3 = _peButton->Add(peTitle);
|
||
|
}
|
||
|
pv->Release();
|
||
|
}
|
||
|
|
||
|
// Cleanup (if necessary).
|
||
|
if (FAILED(hr3))
|
||
|
{
|
||
|
peTitle->Destroy();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(hr2) || SUCCEEDED(hr3))
|
||
|
{
|
||
|
// Add the button to this element.
|
||
|
hr = Add(_peButton);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Failed init icon AND init title for button.
|
||
|
hr = E_FAIL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
_peButton->Destroy();
|
||
|
_peButton = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
DestinationTask::DestinationTask()
|
||
|
{
|
||
|
// Catch unexpected STACK allocations which would break us.
|
||
|
ASSERT(_peButton == NULL);
|
||
|
ASSERT(_pidlDestination == NULL);
|
||
|
ASSERT(_pDUIView == NULL);
|
||
|
ASSERT(_pDefView == NULL);
|
||
|
ASSERT(_hwndRoot == NULL);
|
||
|
|
||
|
_bInfotip = FALSE;
|
||
|
}
|
||
|
|
||
|
DestinationTask::~DestinationTask()
|
||
|
{
|
||
|
if (_bInfotip)
|
||
|
{
|
||
|
// Kill the background infotip task (if any).
|
||
|
if (_pDefView->_pScheduler)
|
||
|
_pDefView->_pScheduler->RemoveTasks(TOID_DVBackgroundInfoTip, (DWORD_PTR)this, FALSE);
|
||
|
|
||
|
// Destroy the infotip.
|
||
|
_pDefView->DestroyInfotip(_hwndRoot, (UINT_PTR)this);
|
||
|
}
|
||
|
|
||
|
ILFree(_pidlDestination); /* NULL ok */
|
||
|
|
||
|
if (_pDUIView)
|
||
|
_pDUIView->Release();
|
||
|
|
||
|
if (_pDefView)
|
||
|
_pDefView->Release();
|
||
|
}
|
||
|
|
||
|
|
||
|
// To use _pDUIView->DelayedNavigation(_psiItemArray, _puiCommand)
|
||
|
// we create this bogus IUICommand impl to get Invoke through
|
||
|
class CInvokePidl : public IUICommand
|
||
|
{
|
||
|
STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
|
||
|
STDMETHODIMP_(ULONG) AddRef();
|
||
|
STDMETHODIMP_(ULONG) Release();
|
||
|
// IUICommand
|
||
|
STDMETHODIMP get_Name(IShellItemArray *psiItemArray, LPWSTR *ppszName) { return E_NOTIMPL; }
|
||
|
STDMETHODIMP get_Icon(IShellItemArray *psiItemArray, LPWSTR *ppszIcon) { return E_NOTIMPL; }
|
||
|
STDMETHODIMP get_Tooltip(IShellItemArray *psiItemArray, LPWSTR *ppszInfotip) { return E_NOTIMPL; }
|
||
|
STDMETHODIMP get_CanonicalName(GUID* pguidCommandName) { return E_NOTIMPL; }
|
||
|
STDMETHODIMP get_State(IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState) { return E_NOTIMPL; }
|
||
|
// Our one real method:
|
||
|
STDMETHODIMP Invoke(IShellItemArray *psiItemArray, IBindCtx *pbc)
|
||
|
{
|
||
|
return _pDUIView->NavigateToDestination(_pidlDestination);
|
||
|
}
|
||
|
|
||
|
friend HRESULT Create_InvokePidl(CDUIView* pDUIView, LPCITEMIDLIST pidl, REFIID riid, void** ppv);
|
||
|
|
||
|
private:
|
||
|
CInvokePidl(CDUIView* pDUIView, LPCITEMIDLIST pidl, HRESULT* phr);
|
||
|
~CInvokePidl();
|
||
|
|
||
|
LONG _cRef;
|
||
|
CDUIView* _pDUIView;
|
||
|
LPITEMIDLIST _pidlDestination;
|
||
|
};
|
||
|
|
||
|
CInvokePidl::CInvokePidl(CDUIView* pDUIView, LPCITEMIDLIST pidl, HRESULT* phr)
|
||
|
{
|
||
|
_cRef = 1;
|
||
|
(_pDUIView = pDUIView)->AddRef();
|
||
|
|
||
|
_pidlDestination = ILClone(pidl);
|
||
|
if (_pidlDestination)
|
||
|
*phr = S_OK;
|
||
|
else
|
||
|
*phr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
CInvokePidl::~CInvokePidl()
|
||
|
{
|
||
|
ILFree(_pidlDestination);
|
||
|
if (_pDUIView)
|
||
|
_pDUIView->Release();
|
||
|
}
|
||
|
|
||
|
HRESULT Create_InvokePidl(CDUIView* pDUIView, LPCITEMIDLIST pidl, REFIID riid, void** ppv)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
*ppv = NULL;
|
||
|
CInvokePidl* p = new CInvokePidl(pDUIView, pidl, &hr);
|
||
|
if (p)
|
||
|
{
|
||
|
hr = p->QueryInterface(riid, ppv);
|
||
|
p->Release();
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CInvokePidl::QueryInterface(REFIID riid, void **ppvObj)
|
||
|
{
|
||
|
static const QITAB qit[] = {
|
||
|
QITABENT(CInvokePidl, IUICommand),
|
||
|
};
|
||
|
|
||
|
return QISearch(this, qit, riid, ppvObj);
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP_(ULONG) CInvokePidl::AddRef()
|
||
|
{
|
||
|
return InterlockedIncrement(&_cRef);
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP_(ULONG) CInvokePidl::Release()
|
||
|
{
|
||
|
if (InterlockedDecrement(&_cRef))
|
||
|
return _cRef;
|
||
|
|
||
|
delete this;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Navigates to the destination pidl
|
||
|
//
|
||
|
// none
|
||
|
|
||
|
HRESULT DestinationTask::InvokePidl()
|
||
|
{
|
||
|
IUICommand* puiInvokePidl;
|
||
|
HRESULT hr = Create_InvokePidl(_pDUIView, _pidlDestination, IID_PPV_ARG(IUICommand, &puiInvokePidl));
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = _pDUIView->DelayedNavigation(NULL, puiInvokePidl);
|
||
|
puiInvokePidl->Release();
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// Displays the context menu
|
||
|
//
|
||
|
// ppt - point to display menu
|
||
|
|
||
|
HRESULT DestinationTask::OnContextMenu(POINT *ppt)
|
||
|
{
|
||
|
HRESULT hr = E_FAIL;
|
||
|
|
||
|
if (!GetHWND())
|
||
|
return hr;
|
||
|
|
||
|
if (ppt->x == -1) // Keyboard context menu
|
||
|
{
|
||
|
Value *pv;
|
||
|
const SIZE *psize = GetExtent(&pv);
|
||
|
ppt->x = psize->cx/2;
|
||
|
ppt->y = psize->cy/2;
|
||
|
pv->Release();
|
||
|
}
|
||
|
|
||
|
POINT pt;
|
||
|
GetRoot()->MapElementPoint(this, ppt, &pt);
|
||
|
|
||
|
ClientToScreen(GetHWND(), &pt);
|
||
|
|
||
|
IContextMenu *pcm;
|
||
|
if (SUCCEEDED(SHGetUIObjectFromFullPIDL(_pidlDestination, GetHWND(), IID_PPV_ARG(IContextMenu, &pcm))))
|
||
|
{
|
||
|
IContextMenu *pcmWrap;
|
||
|
if (SUCCEEDED(Create_ContextMenuWithoutVerbs(pcm, L"link;cut;delete", IID_PPV_ARG(IContextMenu, &pcmWrap))))
|
||
|
{
|
||
|
hr = IUnknown_DoContextMenuPopup(SAFECAST(_pDefView, IShellView2*), pcmWrap, CMF_NORMAL, pt);
|
||
|
|
||
|
pcmWrap->Release();
|
||
|
}
|
||
|
pcm->Release();
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// Shows/hides an Infotip window
|
||
|
//
|
||
|
// bShow - TRUE or FALSE to show or hide the Infotip window
|
||
|
|
||
|
HRESULT DestinationTask::ShowInfotipWindow(BOOL bShow)
|
||
|
{
|
||
|
RECT rect = { 0 };
|
||
|
HRESULT hr;
|
||
|
|
||
|
if (bShow)
|
||
|
{
|
||
|
_pDUIView->CalculateInfotipRect(this, &rect);
|
||
|
if (_bInfotip)
|
||
|
{
|
||
|
// Reposition infotip at position.
|
||
|
hr = _pDefView->RepositionInfotip(_hwndRoot, (UINT_PTR)this, &rect);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Create infotip at position.
|
||
|
hr = GetElementRootHWND(this, &_hwndRoot);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// PreCreateInfotip() on the ui thread.
|
||
|
hr = _pDefView->PreCreateInfotip(_hwndRoot, (UINT_PTR)this, &rect);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// PostCreateInfotip() on a background thread.
|
||
|
CDUIInfotipTask *pTask;
|
||
|
hr = CDUIInfotipTask_CreateInstance(_pDefView, _hwndRoot, (UINT_PTR)this, _pidlDestination, &pTask);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = _pDefView->_AddTask(pTask, TOID_DVBackgroundInfoTip, (DWORD_PTR)this, TASK_PRIORITY_INFOTIP, ADDTASK_ATEND);
|
||
|
pTask->Release();
|
||
|
}
|
||
|
|
||
|
// Persist success or cleanup failure.
|
||
|
if (SUCCEEDED(hr))
|
||
|
_bInfotip = TRUE;
|
||
|
else
|
||
|
_pDefView->DestroyInfotip(_hwndRoot, (UINT_PTR)this);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (_bInfotip)
|
||
|
{
|
||
|
// Reposition infotip at nowhere.
|
||
|
hr = _pDefView->RepositionInfotip(_hwndRoot, (UINT_PTR)this, &rect);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// No infotip == no show!
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// System event handler
|
||
|
//
|
||
|
//
|
||
|
|
||
|
void DestinationTask::OnPropertyChanged(PropertyInfo* ppi, int iIndex, Value* pvOld, Value* pvNew)
|
||
|
{
|
||
|
// Default processing...
|
||
|
Element::OnPropertyChanged(ppi, iIndex, pvOld, pvNew);
|
||
|
|
||
|
// Extended processing for infotip...
|
||
|
if (IsProp(MouseWithin))
|
||
|
ShowInfotipWindow(pvNew->GetBool() && SHShowInfotips());
|
||
|
}
|
||
|
|
||
|
// Event handler
|
||
|
//
|
||
|
// pev - event information
|
||
|
|
||
|
void DestinationTask::OnEvent(Event* pev)
|
||
|
{
|
||
|
if (pev->peTarget == _peButton)
|
||
|
{
|
||
|
if (pev->uidType == Button::Click)
|
||
|
{
|
||
|
InvokePidl();
|
||
|
pev->fHandled = true;
|
||
|
}
|
||
|
else if (pev->uidType == Button::Context)
|
||
|
{
|
||
|
ButtonContextEvent *peButton = reinterpret_cast<ButtonContextEvent *>(pev);
|
||
|
OnContextMenu(&peButton->pt);
|
||
|
pev->fHandled = true;
|
||
|
}
|
||
|
}
|
||
|
Element::OnEvent(pev);
|
||
|
}
|
||
|
|
||
|
// Gadget message callback handler used to return
|
||
|
// the IDropTarget interface
|
||
|
//
|
||
|
// pGMsg - Gadget message
|
||
|
//
|
||
|
// DU_S_COMPLETE if handled
|
||
|
// Host element's return value if not
|
||
|
|
||
|
UINT DestinationTask::MessageCallback(GMSG* pGMsg)
|
||
|
{
|
||
|
EventMsg * pmsg = static_cast<EventMsg *>(pGMsg);
|
||
|
|
||
|
switch (GET_EVENT_DEST(pmsg))
|
||
|
{
|
||
|
case GMF_DIRECT:
|
||
|
case GMF_BUBBLED:
|
||
|
|
||
|
if (pGMsg->nMsg == GM_QUERY)
|
||
|
{
|
||
|
GMSG_QUERYDROPTARGET * pTemp = (GMSG_QUERYDROPTARGET *)pGMsg;
|
||
|
|
||
|
if (pTemp->nCode == GQUERY_DROPTARGET)
|
||
|
{
|
||
|
if (SUCCEEDED(_pDUIView->InitializeDropTarget(_pidlDestination, GetHWND(), &pTemp->pdt)))
|
||
|
{
|
||
|
pTemp->hgadDrop = pTemp->hgadMsg;
|
||
|
return DU_S_COMPLETE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return Element::MessageCallback(pGMsg);
|
||
|
}
|
||
|
|
||
|
// Class information
|
||
|
|
||
|
IClassInfo* DestinationTask::Class = NULL;
|
||
|
HRESULT DestinationTask::Register()
|
||
|
{
|
||
|
return ClassInfo<DestinationTask,Element>::Register(L"DestinationTask", NULL, 0);
|
||
|
}
|