/*--------------------------------------------------------------------------* * * Microsoft Windows * Copyright (C) Microsoft Corporation, 1992 - 1999 * * File: task.cpp * * Contents: Implementation file for CConsoleTask * * History: 05-Oct-98 jeffro Created * *--------------------------------------------------------------------------*/ #include "stdafx.h" #include "regutil.h" #include "tasks.h" #include "nodepath.h" #include "conview.h" #ifdef DBG // Traces CTraceTag tagCTPHTML(TEXT("Console Taskpads"), TEXT("Dump HTML")); #endif extern CEOTSymbol s_rgEOTSymbol[]; /*+-------------------------------------------------------------------------* * class CGlobalConsoleTaskList * * PURPOSE: A global console task list that provides unique IDs for all console tasks * When a task is instantiated, its constructor registers in the global task list, * and obtains a globally unique ID. This ID is unique for the process and should * not be persisted. * The destructor of the task removes it from this list. * * USAGE: Call CGlobalConsoleTaskList::GetConsoleTask to obtain a pointer to the task * that has a specified ID. * Call CConsoleTask::GetUniqueID to get the unique ID for a task. * * Thus, CGlobalConsoleTaskList::GetConsoleTask(pConsoleTask->GetUniqueID()) == pConsoleTask * is always true. *+-------------------------------------------------------------------------*/ class CGlobalConsoleTaskList { private: typedef const CConsoleTask * PCONSOLETASK; typedef std::map t_taskIDmap; public: static DWORD Advise( PCONSOLETASK pConsoleTask) { DWORD dwOut = s_curTaskID++; s_map[pConsoleTask] = dwOut; return dwOut; } static void Unadvise(PCONSOLETASK pConsoleTask) { s_map.erase(pConsoleTask); } static CConsoleTask * GetConsoleTask(DWORD dwID) { t_taskIDmap::iterator iter; for(iter = s_map.begin(); iter != s_map.end(); iter ++) { if(iter->second == dwID) return const_cast(iter->first); } return NULL; } private: CGlobalConsoleTaskList() {}// private, so that it cannot be instantiated static t_taskIDmap s_map; static DWORD s_curTaskID; }; CGlobalConsoleTaskList::t_taskIDmap CGlobalConsoleTaskList::s_map; DWORD CGlobalConsoleTaskList::s_curTaskID = 0; //############################################################################ //############################################################################ // // Implementation of class CConsoleTask // //############################################################################ //############################################################################ /*+-------------------------------------------------------------------------* * CConsoleTask::CConsoleTask * * *--------------------------------------------------------------------------*/ DEBUG_DECLARE_INSTANCE_COUNTER(CConsoleTask); CConsoleTask::CConsoleTask() : m_eConsoleTaskType (eTask_Result), // default ctor for m_strName // default ctor for m_strDescription // default ctor for m_strCommand // default ctor for m_strParameters // default ctor for m_strDirectory m_eWindowState (eState_Restored), // default ctor for m_image m_dwFlags (0), m_bmScopeNode (false), m_fDirty (false), m_pctpOwner (NULL), m_dwUniqueID (CGlobalConsoleTaskList::Advise(this)) // create a unique ID for this task { DEBUG_INCREMENT_INSTANCE_COUNTER(CConsoleTask); } /*+-------------------------------------------------------------------------* * CConsoleTask::CConsoleTask(const CConsoleTask& other) * * PURPOSE: Copy ctor. * * PARAMETERS: const CConsoleTask& other * * NOTE: Calls operator=, cant use default copy ctor (see operator= imp.) * /*+-------------------------------------------------------------------------*/ CConsoleTask::CConsoleTask (const CConsoleTask &rhs): m_dwUniqueID (CGlobalConsoleTaskList::Advise(this)) { DEBUG_INCREMENT_INSTANCE_COUNTER(CConsoleTask); *this = rhs; } /*+-------------------------------------------------------------------------* * * CConsoleTask::GetConsoleTask * * PURPOSE: * * PARAMETERS: * DWORD dwUniqueID : * * RETURNS: * CConsoleTask * * *+-------------------------------------------------------------------------*/ CConsoleTask * CConsoleTask::GetConsoleTask(DWORD dwUniqueID) { return CGlobalConsoleTaskList::GetConsoleTask(dwUniqueID); } /*+-------------------------------------------------------------------------* * * ScReplaceString * * PURPOSE: Replaces all occurrences of the token by its replacement. * * PARAMETERS: * CStr & str : * LPCTSTR szToken : * LPCTSTR szReplacement : * * RETURNS: * static SC * *+-------------------------------------------------------------------------*/ static SC ScReplaceString(CStr &str, LPCTSTR szToken, LPCTSTR szReplacement, bool bMustReplace = true) { DECLARE_SC(sc, TEXT("ScReplaceString")); CStr strTemp = str; str = TEXT(""); int i = strTemp.Find(szToken); if( (-1==i) && bMustReplace) return (sc = E_UNEXPECTED); while(-1!=i) { str += strTemp.Left(i); str += szReplacement; strTemp = strTemp.Mid(i+_tcslen(szToken)); // the remaining string i=strTemp.Find(szToken); } str += strTemp; return sc; } /*+-------------------------------------------------------------------------* * * ScUseJavaScriptStringEntities * * PURPOSE: Use this to create a valid Javascript string. Replaces " by \" and * \ by \\ in the string parameter. * * PARAMETERS: * CStr & str : * * RETURNS: * static SC * *+-------------------------------------------------------------------------*/ static SC ScUseJavaScriptStringEntities(CStr &str) { DECLARE_SC(sc, TEXT("ScUseJavaScriptStringEntities")); // NOTE: don't change the order of these string replacements sc = ScReplaceString(str, TEXT("\\"), TEXT("\\\\"), false); if(sc) return sc; sc = ScReplaceString(str, TEXT("\""), TEXT("\\\""), false); if(sc) return sc; return sc; } /*+-------------------------------------------------------------------------* * * ScUseHTMLEntities * * PURPOSE: Replaces " by " < by < and > by > and & by & in the string parameter. * * PARAMETERS: * CStr & str : * * RETURNS: * static SC * *+-------------------------------------------------------------------------*/ static SC ScUseHTMLEntities(CStr &str) { DECLARE_SC(sc, TEXT("ScUseHTMLEntities")); sc = ScReplaceString(str, TEXT("&"), TEXT("&"), false); if(sc) return sc; sc = ScReplaceString(str, TEXT("\""), TEXT("""), false); if(sc) return sc; sc = ScReplaceString(str, TEXT("<"), TEXT("<"), false); if(sc) return sc; sc = ScReplaceString(str, TEXT(">"), TEXT(">"), false); if(sc) return sc; return sc; } /*+-------------------------------------------------------------------------* * * CConsoleTask::ScGetHTML * * PURPOSE: returns the HTML representation of the task. * * PARAMETERS: * LPCTSTR szFmtHTML : * CStr & strTaskHTML : * bool bUseLargeIcons : Draw in the no-list (large icon) style * bool bUseTextDescriptions : * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CConsoleTask::ScGetHTML(LPCTSTR szFmtHTML, CStr &strTaskHTML, bool bUseLargeIcons, bool bUseTextDescriptions) const { DECLARE_SC(sc, TEXT("CConsoleTask::ScGetHTML")); USES_CONVERSION; // the substitution parameters, in order CStr strTableSpacing = bUseLargeIcons ? TEXT("
") : TEXT(""); int iconWidth = bUseLargeIcons ? 32: 20; int iconHeight = bUseLargeIcons ? 32: 16; // iconWidth and iconHeight repeated int uniqueID = GetUniqueID(); CStr strSmall = bUseLargeIcons ? TEXT("0") : TEXT("1"); CStr strHref; CStr strID; CStr strParameter; CStr strOptionalTitleTag; CStr strOptionalTextDescription; CStr strTaskName = GetName().data(); CStr strDescription = GetDescription().data(); CStr strCommand = GetCommand().data(); // use entities for all strings sc = ScUseHTMLEntities(strTaskName); if(sc) return sc; sc = ScUseHTMLEntities(strDescription); if(sc) return sc; sc = ScUseJavaScriptStringEntities(strCommand); if(sc) return sc; //------ if(bUseTextDescriptions) { strOptionalTextDescription = TEXT("
"); strOptionalTextDescription += strDescription; } else { strOptionalTitleTag.Format(TEXT("title='%s'"), (LPCTSTR) strDescription); } switch(GetTaskType()) { case eTask_Scope: { std::wstring strTemp; // get the bookmark of the scope node. sc = m_bmScopeNode.ScSaveToString(&strTemp); if(sc) return sc; CStr strScopeNodeBookmark = W2CT(strTemp.data()); // make sure that special characters have been converted sc = ScUseJavaScriptStringEntities(strScopeNodeBookmark); if(sc) return sc; strHref.Format(TEXT("external.ExecuteScopeNodeMenuItem(\"%s\", \"%s\");"), (LPCTSTR)strCommand, (LPCTSTR)strScopeNodeBookmark); } strID=L"ScopeTask"; break; case eTask_Result: strHref.Format(TEXT("external.ExecuteSelectionMenuItem(\"%s\");"), (LPCTSTR)strCommand); strParameter = strCommand; strID = TEXT("ResultTask"); break; case eTask_CommandLine: { strParameter = GetParameters().data(); sc = ScUseJavaScriptStringEntities(strParameter); if(sc) return sc; CStr strDirectory = GetDirectory().data(); sc = ScUseJavaScriptStringEntities(strDirectory); if(sc) return sc; // get the window state CStr strWindowState; if(GetWindowState() ==eState_Restored) strWindowState = XML_ENUM_WINDOW_STATE_RESTORED; else if(GetWindowState() == eState_Minimized) strWindowState = XML_ENUM_WINDOW_STATE_MINIMIZED; else strWindowState = XML_ENUM_WINDOW_STATE_MAXIMIZED; strHref.Format(TEXT("external.ExecuteShellCommand(\"%s\", \"%s\", ParseParameters(\"%s\"), \"%s\");"), (LPCTSTR)strCommand, (LPCTSTR)strDirectory, (LPCTSTR)strParameter, (LPCTSTR)strWindowState); } strID=L"CommandLineTask"; break; case eTask_Target: strHref.Format(TEXT("external.ExecuteScopeNodeMenuItem(\"%s\");"), (LPCTSTR)strCommand); strParameter = strCommand; strID = L"TargetTask"; break; case eTask_Favorite: { std::wstring strTemp; // save the memento to a string sc = const_cast(&m_memento)->ScSaveToString(&strTemp); if(sc) return sc; CStr strMemento = W2CT(strTemp.data()); sc = ScUseJavaScriptStringEntities(strMemento); if(sc) return sc; strHref.Format(TEXT("external.ViewMemento(\"%s\");"), (LPCTSTR)strMemento); } strID=L"FavoriteTask"; break; default: break; } strTaskHTML.Format(szFmtHTML, (LPCTSTR) strTableSpacing, iconWidth, iconHeight, uniqueID, iconWidth, iconHeight, uniqueID, (LPCTSTR) strSmall, uniqueID, uniqueID, (LPCTSTR) strID, (LPCTSTR) strParameter, (LPCTSTR) strOptionalTitleTag, (LPCTSTR)strTaskName, (LPCTSTR) strOptionalTextDescription, uniqueID, uniqueID, uniqueID, (LPCTSTR) strHref); Trace(tagCTPHTML, TEXT("%s"), (LPCTSTR)strTaskHTML); return sc; } /*+-------------------------------------------------------------------------* * * CConsoleTask::IsDirty * * PURPOSE: Determines whether the task needs to be saved. * * RETURNS: * bool * *+-------------------------------------------------------------------------*/ bool CConsoleTask::IsDirty() const { TraceDirtyFlag(TEXT("CConsoleTask"), m_fDirty); return (m_fDirty); } /*+-------------------------------------------------------------------------* * CConsoleTask::operator = * * PURPOSE: Assignment operator * * PARAMETERS: const CConsoleTask& rhs * * RETURNS: * CConsoleTask & * /*+-------------------------------------------------------------------------*/ CConsoleTask & CConsoleTask::operator =(const CConsoleTask& rhs) { if (this != &rhs) { m_eConsoleTaskType = rhs.m_eConsoleTaskType; m_strName = rhs.m_strName; m_strDescription = rhs.m_strDescription; m_strCommand = rhs.m_strCommand; m_strParameters = rhs.m_strParameters; m_strDirectory = rhs.m_strDirectory; m_eWindowState = rhs.m_eWindowState; m_dwFlags = rhs.m_dwFlags; m_bmScopeNode = rhs.m_bmScopeNode; m_dwSymbol = rhs.m_dwSymbol; m_smartIconCustomLarge = rhs.m_smartIconCustomLarge; m_smartIconCustomSmall = rhs.m_smartIconCustomSmall; m_memento = rhs.m_memento; m_fDirty = rhs.m_fDirty; m_pctpOwner = rhs.m_pctpOwner; // m_dwUniqueID = rhs.m_dwUniqueID; DO NOT copy this ID } return *this; } /*+-------------------------------------------------------------------------* * * CConsoleTask::operator == * * PURPOSE: Equality operator. Checks that the command string is * equal to the given menuitem's Path or Language Independent Path. * *+-------------------------------------------------------------------------*/ bool CConsoleTask::operator==(const CMenuItem & menuItem) const { // check that the command string matches either the path or the language independent path. if( (m_strCommand == menuItem.GetPath()) || (m_strCommand == menuItem.GetLanguageIndependentPath() ) ) return true; return false; } /*+-------------------------------------------------------------------------* * CConsoleTask::~CConsoleTask * * *--------------------------------------------------------------------------*/ CConsoleTask::~CConsoleTask () { DEBUG_DECREMENT_INSTANCE_COUNTER(CConsoleTask); CGlobalConsoleTaskList::Unadvise(this); // remove this task from the list. } /*+-------------------------------------------------------------------------* * * CConsoleTask::HasCustomIcon * * PURPOSE: Returns whether the task has a custom icon * * RETURNS: * bool * *+-------------------------------------------------------------------------*/ bool CConsoleTask::HasCustomIcon() const { if((HICON)m_smartIconCustomLarge != NULL) { ASSERT((HICON)m_smartIconCustomSmall != NULL); return true; } return false; } /*+-------------------------------------------------------------------------* * * CConsoleTask::Reset * * PURPOSE: * * RETURNS: * void * *+-------------------------------------------------------------------------*/ void CConsoleTask::ResetUI() { m_bmScopeNode.ResetUI(); } /*+-------------------------------------------------------------------------* * * CConsoleTask::SetSymbol * * PURPOSE: * * PARAMETERS: * DWORD dwSymbol : * * RETURNS: * void * *+-------------------------------------------------------------------------*/ void CConsoleTask::SetSymbol(DWORD dwSymbol) { m_dwSymbol = dwSymbol; m_smartIconCustomSmall.Release(); m_smartIconCustomLarge.Release(); SetDirty(); } /*+-------------------------------------------------------------------------* * * CConsoleTask::SetCustomIcon * * PURPOSE: * * PARAMETERS: * CSmartIcon& iconSmall : * CSmartIcon& iconLarge : * * RETURNS: * void * *+-------------------------------------------------------------------------*/ void CConsoleTask::SetCustomIcon(CSmartIcon& iconSmall, CSmartIcon& iconLarge) { m_smartIconCustomSmall = iconSmall; m_smartIconCustomLarge = iconLarge; SetDirty(); } /*+-------------------------------------------------------------------------* * CConsoleTask::Enable * * Sets the enable state for a task. *--------------------------------------------------------------------------*/ void CConsoleTask::Enable (bool fEnable) { if (fEnable) m_dwFlags &= ~eFlag_Disabled; else m_dwFlags |= eFlag_Disabled; SetDirty (); } void CConsoleTask::Draw (HDC hdc, RECT *lpRect, bool bSmall) const // Draw into a DC. { if(HasCustomIcon()) { DrawIconEx(hdc, lpRect->left, lpRect->top, bSmall ? m_smartIconCustomSmall : m_smartIconCustomLarge, bSmall? 16 : 32, bSmall? 16 : 32, 0, NULL, DI_NORMAL); return; } for(int i = 0; i< NUM_SYMBOLS; i++) { if(s_rgEOTSymbol[i].GetValue() == m_dwSymbol) { s_rgEOTSymbol[i].Draw(hdc, lpRect, bSmall); return; } } /* * if we get here, we couldn't find the EOT symbol matching m_dwSymbol */ ASSERT (false); } /*+-------------------------------------------------------------------------* * CConsoleTask::SetName * * *--------------------------------------------------------------------------*/ void CConsoleTask::SetName (const tstring& strName) { if (m_strName != strName) { m_strName = strName; SetDirty (); } } /*+-------------------------------------------------------------------------* * CConsoleTask::SetDescription * * *--------------------------------------------------------------------------*/ void CConsoleTask::SetDescription (const tstring& strDescription) { if (m_strDescription != strDescription) { m_strDescription = strDescription; SetDirty (); } } /*+-------------------------------------------------------------------------* * CConsoleTask::SetCommand * * *--------------------------------------------------------------------------*/ void CConsoleTask::SetCommand (const tstring& strCommand) { if (m_strCommand != strCommand) { m_strCommand = strCommand; SetDirty (); } } /*+-------------------------------------------------------------------------* * CConsoleTask::SetParameters * * *--------------------------------------------------------------------------*/ void CConsoleTask::SetParameters (const tstring& strParameters) { if (m_strParameters != strParameters) { m_strParameters = strParameters; SetDirty (); } } /*+-------------------------------------------------------------------------* * CConsoleTask::SetDirectory * * *--------------------------------------------------------------------------*/ void CConsoleTask::SetDirectory (const tstring& strDirectory) { if (m_strDirectory != strDirectory) { m_strDirectory = strDirectory; SetDirty (); } } void CConsoleTask::SetMemento(const CMemento &memento) { if( m_memento != memento) { m_memento = memento; SetDirty(); } } /*+-------------------------------------------------------------------------* * CConsoleTask::SetWindowState * * *--------------------------------------------------------------------------*/ void CConsoleTask::SetWindowState (eWindowState eNewState) { if (m_eWindowState != eNewState) { m_eWindowState = eNewState; SetDirty (); } } /*+-------------------------------------------------------------------------* * CConsoleTask::RetargetScopeNode * * PURPOSE: Sets the target scope node for the task. Note: the task must be * of type eTask_Scope. * * PARAMETERS: * CNode * pNewNode: * * RETURNS: * bool */ /*+-------------------------------------------------------------------------*/ bool CConsoleTask::RetargetScopeNode(CNode *pNewNode) { bool fRet = TRUE; ASSERT(GetTaskType() == eTask_Scope); CMTNode* pMTNewNode = (pNewNode) ? pNewNode->GetMTNode() : NULL; m_bmScopeNode.ScRetarget(pMTNewNode, false /*bFastRetrievalOnly*/); SetDirty(); return fRet; } /*+-------------------------------------------------------------------------* * CConsoleTask::GetScopeNode * * PURPOSE: * * PARAMETERS: * IScopeTree * pScopeTree: * * RETURNS: * CMTNode * * /*+-------------------------------------------------------------------------*/ CMTNode * CConsoleTask::GetScopeNode(IScopeTree *pScopeTree) const { DECLARE_SC(sc, TEXT("CConsoleTask::GetScopeNode")); CMTNode *pMTNode = NULL; bool bExactMatchFound = false; // out value from ScGetMTNode, unused sc = m_bmScopeNode.ScGetMTNode(true /*bExactMatchRequired*/, &pMTNode, bExactMatchFound); if(sc.IsError()) return NULL; return (pMTNode); } /*+-------------------------------------------------------------------------* * CConsoleTask::GetScopeNode * * PURPOSE: * * PARAMETERS: * CViewData * pViewData: * * RETURNS: * CNode * /*+-------------------------------------------------------------------------*/ std::auto_ptr CConsoleTask::GetScopeNode(CViewData *pViewData) const { return m_bmScopeNode.GetNode(pViewData); } /*+-------------------------------------------------------------------------* * * CConsoleTask::Persist * * PURPOSE: Persists the console task to the specified persistor. * * * PARAMETERS: * CPersistor & persistor : * * RETURNS: * void * *+-------------------------------------------------------------------------*/ void CConsoleTask::Persist(CPersistor &persistor) { persistor.PersistString(XML_ATTR_TASK_NAME, m_strName); // define the table to map enumeration values to strings static const EnumLiteral mappedTaskTypes[] = { { eTask_Scope, XML_ENUM_TASK_TYPE_SCOPE }, { eTask_Result, XML_ENUM_TASK_TYPE_RESULT }, { eTask_CommandLine, XML_ENUM_TASK_TYPE_COMMANDLINE }, { eTask_Target, XML_ENUM_TASK_TYPE_TARGET }, { eTask_Favorite, XML_ENUM_TASK_TYPE_FAVORITE }, }; // create wrapper to persist flag values as strings CXMLEnumeration taskTypePersistor(m_eConsoleTaskType, mappedTaskTypes, countof(mappedTaskTypes)); // persist the wrapper persistor.PersistAttribute(XML_ATTR_TASK_TYPE, taskTypePersistor); persistor.PersistString(XML_ATTR_TASK_DESCRIPTION, m_strDescription); { /* this section creates NOTE: either the id or the images are present. */ // create a child element for the symbol CPersistor persistorSymbol(persistor, XML_TAG_EOT_SYMBOL_INFO); if(persistorSymbol.IsLoading()) { m_dwSymbol = (DWORD)-1; // initialize } if(persistorSymbol.IsLoading() || (persistorSymbol.IsStoring() && !HasCustomIcon() ) ) { // save the "ID" attribute only if there is no icon persistorSymbol.PersistAttribute(XML_ATTR_EOT_SYMBOL_DW_SYMBOL, m_dwSymbol, attr_optional); } if((persistorSymbol.IsStoring() && HasCustomIcon()) || (persistorSymbol.IsLoading() && (m_dwSymbol == (DWORD) -1) ) ) { persistorSymbol.Persist (m_smartIconCustomSmall, XML_NAME_ICON_SMALL); persistorSymbol.Persist (m_smartIconCustomLarge, XML_NAME_ICON_LARGE); } } persistor.PersistAttribute(XML_ATTR_TASK_COMMAND, m_strCommand); // define the table to map enumeration values to strings static const EnumLiteral mappedTaskFlags[] = { { eFlag_Disabled, XML_BITFLAG_TASK_DISABLED }, }; // create wrapper to persist flag values as strings CXMLBitFlags taskFlagPersistor(m_dwFlags, mappedTaskFlags, countof(mappedTaskFlags)); // persist the wrapper persistor.PersistAttribute(XML_ATTR_TASK_FLAGS, taskFlagPersistor); switch (m_eConsoleTaskType) { case eTask_Scope: persistor.Persist(m_bmScopeNode); break; case eTask_CommandLine: { CPersistor persistorCmd(persistor, XML_TAG_TASK_CMD_LINE); persistorCmd.PersistAttribute(XML_ATTR_TASK_CMD_LINE_DIR, m_strDirectory); // define the table to map enumeration values to strings static const EnumLiteral windowStates[] = { { eState_Restored, XML_ENUM_WINDOW_STATE_RESTORED }, { eState_Minimized, XML_ENUM_WINDOW_STATE_MINIMIZED }, { eState_Maximized, XML_ENUM_WINDOW_STATE_MAXIMIZED }, }; // create wrapper to persist flag values as strings CXMLEnumeration windowStatePersistor(m_eWindowState, windowStates, countof(windowStates)); // persist the wrapper persistorCmd.PersistAttribute(XML_ATTR_TASK_CMD_LINE_WIN_ST, windowStatePersistor); persistorCmd.PersistAttribute(XML_ATTR_TASK_CMD_LINE_PARAMS, m_strParameters); break; } case eTask_Favorite: persistor.Persist(m_memento); break; } // either read or saved - not dirty after the operation SetDirty(false); } /*+-------------------------------------------------------------------------* * CConsoleTask::ReadSerialObject * * *--------------------------------------------------------------------------*/ HRESULT CConsoleTask::ReadSerialObject (IStream &stm, UINT nVersion /*,LARGE_INTEGER nBytes*/) { HRESULT hr = S_FALSE; // assume unknown version if (nVersion == 1) { try { // ugly hackery required to extract directly into an enum stm >> *((int *) &m_eConsoleTaskType); stm >> m_strName; stm >> m_strDescription; // legacy task symbol info { // this must be BOOL not bool to occupy the same amount of space as in legacy consoles // See Bug #101253 BOOL bLegacyUseMMCSymbols = TRUE; // a now obsolete field, read for console file compatibility tstring strFileLegacy, strFontLegacy; stm >> m_dwSymbol; stm >> bLegacyUseMMCSymbols; stm >> strFileLegacy; // obsolete stm >> strFontLegacy; // obsolete } stm >> m_strCommand; stm >> m_dwFlags; switch (m_eConsoleTaskType) { case eTask_Scope: stm >> m_bmScopeNode; break; case eTask_CommandLine: stm >> m_strDirectory; // ugly hackery required to extract directly into an enum stm >> *((int *) &m_eWindowState); stm >> m_strParameters; break; case eTask_Favorite: hr = m_memento.Read(stm); if(FAILED(hr)) return hr; break; } hr = S_OK; } catch (_com_error& err) { hr = err.Error(); ASSERT (false && "Caught _com_error"); } } return (hr); } /*+-------------------------------------------------------------------------* * CConsoleTaskpad::CConsoleTaskpad * * *--------------------------------------------------------------------------*/ CConsoleTaskpad::CConsoleTaskpad (CNode* pTargetNode /*=NULL*/) : m_listSize(eSize_Default), // the default space given to a taskpad. m_guidNodeType(GUID_NULL), m_guidID(GUID_NULL), m_bmTargetNode(), m_pMTNodeTarget(NULL), m_bNodeSpecific(false), m_dwOrientation(TVO_VERTICAL), // the default is a vertical taskpad for consistency with the Extended view. m_bReplacesDefaultView(true) // taskpads do not show the normal tab by default. { Retarget (pTargetNode); HRESULT hr = CoCreateGuid(&m_guidID); ASSERT(SUCCEEDED(hr)); SetDirty (false); } bool CConsoleTaskpad::IsValid(CNode *pNode) const { ASSERT(pNode != NULL); if(!HasTarget()) return true; // a taskpad without a target is valid for any node. $REVIEW if(!pNode) return false; // Cannot use a taskpad with a target. if(IsNodeSpecific()) { // use this taskpad if it is targetted at the same node. $OPTIMIZE. return (*pNode->GetMTNode()->GetBookmark() == m_bmTargetNode); } else { GUID guid; HRESULT hr = pNode->GetNodeType(&guid); if(FAILED(hr)) return false; // don't use this taskpad. return (MatchesNodeType(guid)); // use only if node types match. } } static CStr g_szTaskpadCommonHTMLTemplate; static CStr g_szVerticalTaskpadHTMLTemplate; static CStr g_szHorizontalTaskpadHTMLTemplate; static CStr g_szNoResultsTaskpadHTMLTemplate; static CStr g_szTaskHTMLTemplate; /*+-------------------------------------------------------------------------* * * ScLoadHTMLTemplate * * PURPOSE: * * PARAMETERS: * HINSTANCE hinstLibrary : * LPCTSTR szHTMLTemplateResourceName : * CStr& str : * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC ScLoadHTMLTemplate(HINSTANCE hinstLibrary, LPCTSTR szHTMLTemplateResourceName, CStr& str) { DECLARE_SC(sc, TEXT("ScLoadHTMLTemplate")); sc = ScCheckPointers(hinstLibrary, szHTMLTemplateResourceName); if(sc) return sc; HRSRC hFindRes = ::FindResource(hinstLibrary, szHTMLTemplateResourceName, RT_HTML); if(!hFindRes) return (sc = E_UNEXPECTED); DWORD dwResSize = ::SizeofResource(hinstLibrary, hFindRes); if(!dwResSize) return (sc = E_UNEXPECTED); HGLOBAL hRes = ::LoadResource(hinstLibrary, hFindRes); ASSERT(hRes); char *pvRes = (char *)::LockResource(hRes); // no need to Unlock the resource - see the SDK entry for LockResource sc = ScCheckPointers(pvRes); if(sc) return sc; std::string strTemp; // initially create an ANSI string strTemp.assign(pvRes, dwResSize); strTemp+="\0"; // null terminate it USES_CONVERSION; str = A2CT(strTemp.data()); return sc; } /*+-------------------------------------------------------------------------* * * ScLoadHTMLTemplates * * PURPOSE: * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC ScLoadHTMLTemplates() { DECLARE_SC(sc, TEXT("ScLoadHTMLTemplates")); static BOOL bInitialized = false; if(bInitialized) return sc; // load the library into memory. TCHAR szBuffer[MAX_PATH]; ::GetModuleFileName (_Module.GetModuleInstance(), szBuffer, countof (szBuffer)); HINSTANCE hinstLibrary = ::LoadLibraryEx(szBuffer, 0, LOAD_LIBRARY_AS_DATAFILE); if(!hinstLibrary) return (sc = E_UNEXPECTED); sc = ScLoadHTMLTemplate(hinstLibrary, TEXT("CTPCOMMON.HTM"), g_szTaskpadCommonHTMLTemplate); if(sc) goto Error; sc = ScLoadHTMLTemplate(hinstLibrary, TEXT("CTPVERT.HTM"), g_szVerticalTaskpadHTMLTemplate); if(sc) goto Error; sc = ScLoadHTMLTemplate(hinstLibrary, TEXT("CTPHORIZ.HTM"), g_szHorizontalTaskpadHTMLTemplate); if(sc) goto Error; sc = ScLoadHTMLTemplate(hinstLibrary, TEXT("CTPNORESULTS.HTM"), g_szNoResultsTaskpadHTMLTemplate); if(sc) goto Error; sc = ScLoadHTMLTemplate(hinstLibrary, TEXT("CTPTASK.HTM"), g_szTaskHTMLTemplate); if(sc) goto Error; bInitialized = true; Cleanup: FreeLibrary(hinstLibrary); return sc; Error: sc = E_UNEXPECTED; goto Cleanup; } /*+-------------------------------------------------------------------------* * * CConsoleTaskpad::ScGetHTML * * PURPOSE: * * PARAMETERS: * CStr & strTaskpadHTML : * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CConsoleTaskpad::ScGetHTML(CStr &strTaskpadHTML) const { DECLARE_SC(sc, TEXT("CConsoleTaskpad::ScGetHTML")); sc = ScLoadHTMLTemplates(); if(sc) return sc; CStr strTasksHTML; // get the HTML for all the tasks for (TaskConstIter it = m_Tasks.begin(); it != m_Tasks.end(); ++it) { CStr strTemp; sc = it->ScGetHTML(g_szTaskHTMLTemplate, strTemp, GetOrientation() & TVO_NO_RESULTS /*bUseLargeIcons*/, GetOrientation() & TVO_DESCRIPTIONS_AS_TEXT); if(sc) return sc; strTasksHTML += strTemp; } strTaskpadHTML = g_szTaskpadCommonHTMLTemplate; // append the orientation-specific portion CStr *pstrOrientationSpecificHTML = NULL; if(GetOrientation() & TVO_HORIZONTAL) pstrOrientationSpecificHTML = &g_szHorizontalTaskpadHTMLTemplate; else if (GetOrientation() & TVO_VERTICAL) pstrOrientationSpecificHTML = &g_szVerticalTaskpadHTMLTemplate; else pstrOrientationSpecificHTML = &g_szNoResultsTaskpadHTMLTemplate; sc = ScCheckPointers(pstrOrientationSpecificHTML, E_UNEXPECTED); if(sc) return sc; // this replacement must be done first sc = ScReplaceString(strTaskpadHTML, TEXT("@@ORIENTATIONSPECIFICHTML@@"), *pstrOrientationSpecificHTML); if(sc) return sc; sc = ScReplaceString(strTaskpadHTML, TEXT("@@TASKS@@"), strTasksHTML); if(sc) return sc; sc = ScReplaceString(strTaskpadHTML, TEXT("@@TASKWIDTH@@"), GetOrientation() & TVO_VERTICAL ? TEXT("100%") : TEXT("30%")); // only one task per row for vertical taskpads if(sc) return sc; CStr strName = GetName().data(); sc = ScUseHTMLEntities(strName); if(sc) return sc; CStr strDescription = GetDescription().data(); sc = ScUseHTMLEntities(strDescription); if(sc) return sc; sc = ScReplaceString(strTaskpadHTML, TEXT("@@CONSOLETASKPADNAME@@"), strName); if(sc) return sc; sc = ScReplaceString(strTaskpadHTML, TEXT("@@CONSOLETASKPADDESCRIPTION@@"), strDescription); if(sc) return sc; if (GetOrientation() & TVO_VERTICAL) { // small, medium and large list sizes correspond to taskpad areas of 262, 212, and 166 pixels respectively CStr strLeftPaneWidth; if(GetListSize()==eSize_Small) strLeftPaneWidth=TEXT("262"); if(GetListSize()==eSize_Medium) strLeftPaneWidth=TEXT("212"); if(GetListSize()==eSize_Large) strLeftPaneWidth=TEXT("166"); sc = ScReplaceString(strTaskpadHTML, TEXT("@@LEFTPANEWIDTH@@"), strLeftPaneWidth); if(sc) return sc; } else if (GetOrientation() & TVO_HORIZONTAL) { // small, medium and large list sizes correspond to taskpad heights of 200, 150, and 100 pixels respectively CStr strBottomPaneHeight; if(GetListSize()==eSize_Small) strBottomPaneHeight=TEXT("200"); if(GetListSize()==eSize_Medium) strBottomPaneHeight=TEXT("150"); if(GetListSize()==eSize_Large) strBottomPaneHeight=TEXT("100"); sc = ScReplaceString(strTaskpadHTML, TEXT("@@BOTTOMPANEHEIGHT@@"), strBottomPaneHeight); if(sc) return sc; } return sc; } /*+-------------------------------------------------------------------------* * * CConsoleTaskpad::Reset * * PURPOSE: * * RETURNS: * void * *+-------------------------------------------------------------------------*/ void CConsoleTaskpad::ResetUI() { // reset all the contained tasks. for (TaskIter iter = BeginTask(); iter!=EndTask(); ++iter) { iter->ResetUI(); } // reset the member bookmark m_bmTargetNode.ResetUI(); } /*+-------------------------------------------------------------------------* * CConsoleTaskpad::Retarget * * *--------------------------------------------------------------------------*/ bool CConsoleTaskpad::Retarget (CMTNode* pMTNewNode, bool fReset) { /* * if we were given a new node... */ if (pMTNewNode != NULL) { // Ensure the MTNode is initialized. if (!pMTNewNode->IsInitialized()) { HRESULT hr = pMTNewNode->Init(); ASSERT(SUCCEEDED(hr)); } /* * ...if we've already been targeted to a particular node * type, prevent retargeting to a different node type */ if ( (!fReset) && (m_guidNodeType != GUID_NULL)) { GUID guidNewNodeType; pMTNewNode->GetNodeType (&guidNewNodeType); if (guidNewNodeType != m_guidNodeType) return (false); } /* * otherwise, this is the first non-NULL node we've been * targeted to; get its node type */ else pMTNewNode->GetNodeType (&m_guidNodeType); /* * If this is a new taskpad, default the taskpad's name * to the target node's display name. The taskpad * description and tooltip default to empty. */ if (m_strName.str().empty() || fReset) { m_strName = pMTNewNode->GetDisplayName(); ASSERT (m_strDescription.str().empty()); ASSERT (m_strTooltip.str().empty()); } } m_bmTargetNode.ScRetarget(pMTNewNode, false /*bFastRetrievalOnly*/); m_pMTNodeTarget = pMTNewNode; SetDirty (); return (true); } bool CConsoleTaskpad::Retarget (CNode* pNewNode) { CMTNode* pMTNewNode = (pNewNode != NULL) ? pNewNode->GetMTNode() : NULL; return (Retarget (pMTNewNode)); } /*+-------------------------------------------------------------------------* * CConsoleTaskpad::SetName * * *--------------------------------------------------------------------------*/ void CConsoleTaskpad::SetName (const tstring& strName) { SetStringMember (m_strName, strName); } /*+-------------------------------------------------------------------------* * CConsoleTaskpad::SetDescription * * *--------------------------------------------------------------------------*/ void CConsoleTaskpad::SetDescription (const tstring& strDescription) { SetStringMember (m_strDescription, strDescription); } void CConsoleTaskpad::SetListSize(const ListSize listSize) { m_listSize = listSize; SetDirty(); } /*+-------------------------------------------------------------------------* * CConsoleTaskpad::SetToolTip * * *--------------------------------------------------------------------------*/ void CConsoleTaskpad::SetToolTip (const tstring& strTooltip) { SetStringMember (m_strTooltip, strTooltip); } void CConsoleTaskpad::SetNodeSpecific (bool bNodeSpecific) { m_bNodeSpecific = bNodeSpecific; SetDirty(); } void CConsoleTaskpad::SetReplacesDefaultView(bool bReplacesDefaultView) { m_bReplacesDefaultView = bReplacesDefaultView; SetDirty(); } /*+-------------------------------------------------------------------------* * CConsoleTaskpad::SetStringMember * * Changes the value of a string member variable, and marks the taskpad * dirty, if and only if the new value is different than the old value. *--------------------------------------------------------------------------*/ void CConsoleTaskpad::SetStringMember ( CStringTableString& strMember, const tstring& strNewValue) { if (strMember != strNewValue) { strMember = strNewValue; SetDirty (); } } /*+-------------------------------------------------------------------------* * CConsoleTaskpad::AddTask * * *--------------------------------------------------------------------------*/ CConsoleTaskpad::TaskIter CConsoleTaskpad::AddTask (const CConsoleTask& task) { return (InsertTask (m_Tasks.end(), task)); } /*+-------------------------------------------------------------------------* * CConsoleTaskpad::InsertTask * * *--------------------------------------------------------------------------*/ CConsoleTaskpad::TaskIter CConsoleTaskpad::InsertTask ( TaskIter itTaskBeforeWhichToInsert, const CConsoleTask& task) { TaskIter itInserted = m_Tasks.insert (itTaskBeforeWhichToInsert, task); SetDirty (); return (itInserted); } /*+-------------------------------------------------------------------------* * CConsoleTaskpad::EraseTask * * *--------------------------------------------------------------------------*/ CConsoleTaskpad::TaskIter CConsoleTaskpad::EraseTask ( TaskIter itErase) { SetDirty (); return (m_Tasks.erase (itErase)); } /*+-------------------------------------------------------------------------* * CConsoleTaskpad::EraseTasks * * *--------------------------------------------------------------------------*/ CConsoleTaskpad::TaskIter CConsoleTaskpad::EraseTasks ( TaskIter itFirst, TaskIter itLast) { SetDirty (); return (m_Tasks.erase (itFirst, itLast)); } /*+-------------------------------------------------------------------------* * CConsoleTaskpad::ClearTasks * * *--------------------------------------------------------------------------*/ void CConsoleTaskpad::ClearTasks () { SetDirty (); m_Tasks.clear (); } /*+-------------------------------------------------------------------------* * CConsoleTaskpad::IsDirty * * Determines if this taskpad or any of its contained tasks is are dirty. *--------------------------------------------------------------------------*/ bool CConsoleTaskpad::IsDirty () const { /* * if the taskpad is dirty, short out */ if (m_fDirty) { TraceDirtyFlag(TEXT("CConsoleTaskpad"), true); return (true); } /* * the taskpad is clean, check each task */ for (TaskConstIter it = m_Tasks.begin(); it != m_Tasks.end(); ++it) { if (it->IsDirty()) { TraceDirtyFlag(TEXT("CConsoleTaskpad"), true); return (true); } } TraceDirtyFlag(TEXT("CConsoleTaskpad"), false); return (false); } /*+-------------------------------------------------------------------------* * CConsoleTaskpad::GetTargetMTNode * * *--------------------------------------------------------------------------*/ CMTNode* CConsoleTaskpad::GetTargetMTNode (IScopeTree* pScopeTree) { DECLARE_SC(sc, TEXT("CConsoleTaskpad::GetTargetMTNode")); if(!HasTarget()) return NULL; if(!m_pMTNodeTarget) { CMTNode *pMTNode = NULL; bool bExactMatchFound = false; // out value from ScGetMTNode, unused sc = m_bmTargetNode.ScGetMTNode(true /*bExactMatchRequired*/, &pMTNode, bExactMatchFound); if(sc.IsError() || !pMTNode) return NULL; m_pMTNodeTarget = pMTNode; } return (m_pMTNodeTarget); } /*+-------------------------------------------------------------------------* * * CConsoleTaskpad::Persist * * PURPOSE: Persists the console taskpad to the specified persistor. * * PARAMETERS: * CPersistor & persistor : * * RETURNS: * void * *+-------------------------------------------------------------------------*/ void CConsoleTaskpad::Persist(CPersistor &persistor) { persistor.PersistString(XML_ATTR_TASKPAD_NAME, m_strName); persistor.PersistString(XML_ATTR_TASKPAD_DESCRIPTION, m_strDescription); persistor.PersistString(XML_ATTR_TASKPAD_TOOLTIP, m_strTooltip); // define the table to map enumeration values to strings static const EnumLiteral mappedSize[] = { { eSize_Large, XML_ENUM_LIST_SIZE_LARGE }, { eSize_Medium, XML_ENUM_LIST_SIZE_MEDIUM }, { eSize_None, XML_ENUM_LIST_SIZE_NONE }, { eSize_Small, XML_ENUM_LIST_SIZE_SMALL }, }; // create wrapper to persist flag values as strings CXMLEnumeration listSizePersistor(m_listSize, mappedSize, countof(mappedSize)); // initialize the value suitably if(persistor.IsLoading()) m_listSize = eSize_Default; // persist the wrapper persistor.PersistAttribute(XML_ATTR_TASKPAD_LIST_SIZE, listSizePersistor, attr_optional); // optional because this was introduced late persistor.PersistAttribute(XML_ATTR_TASKPAD_NODE_SPECIFIC, CXMLBoolean(m_bNodeSpecific)); persistor.PersistAttribute(XML_ATTR_REPLACES_DEFAULT_VIEW, CXMLBoolean(m_bReplacesDefaultView), attr_optional); // define the table to map enumeration values to strings static const EnumLiteral mappedOrientation[] = { { TVO_HORIZONTAL, XML_BITFLAG_TASK_ORIENT_HORIZONTAL }, { TVO_VERTICAL, XML_BITFLAG_TASK_ORIENT_VERTICAL }, { TVO_NO_RESULTS, XML_BITFLAG_TASK_ORIENT_NO_RESULTS }, { TVO_DESCRIPTIONS_AS_TEXT, XML_BITFLAG_TASK_ORIENT_DESCRIPTIONS_AS_TEXT }, }; // create wrapper to persist flag values as strings CXMLBitFlags orientationPersistor(m_dwOrientation, mappedOrientation, countof(mappedOrientation)); // persist the wrapper persistor.PersistAttribute(XML_ATTR_TASKPAD_ORIENTATION, orientationPersistor ); persistor.Persist(m_Tasks); persistor.PersistAttribute(XML_ATTR_TASKPAD_NODE_TYPE, m_guidNodeType); persistor.PersistAttribute(XML_ATTR_TASKPAD_ID, m_guidID); persistor.Persist(m_bmTargetNode, XML_NAME_TARGET_NODE); // either read or saved - not dirty after the operation SetDirty(false); } /*+-------------------------------------------------------------------------* * CConsoleTaskpad::ReadSerialObject * * *--------------------------------------------------------------------------*/ HRESULT CConsoleTaskpad::ReadSerialObject (IStream &stm, UINT nVersion) { HRESULT hr = S_FALSE; // assume unknown version if(nVersion==1) { try { do // not a loop { bool fLegacyHasTarget = true; // an unused field UINT visualPercent = 25; // replaced by m_listSize stm >> m_strName; stm >> m_strDescription; stm >> m_strTooltip; stm >> visualPercent; m_listSize = eSize_Medium; if(visualPercent==25) m_listSize = eSize_Large; else if(visualPercent==75) m_listSize = eSize_Small; stm >> m_bNodeSpecific; m_bReplacesDefaultView = false; // this was introduced in mmc2.0. stm >> m_dwOrientation; hr = ::Read(stm, m_Tasks); BREAK_ON_FAIL (hr); stm >> m_guidNodeType; stm >> m_guidID; stm >> fLegacyHasTarget; stm >> m_bmTargetNode; // legacy task symbol info { BOOL bLegacyUseMMCSymbols = TRUE; // a now obsolete field, read for console file compatibility tstring strFileLegacy, strFontLegacy; DWORD dwSymbol = 0; stm >> dwSymbol; stm >> bLegacyUseMMCSymbols; stm >> strFileLegacy; // obsolete stm >> strFontLegacy; // obsolete } hr = S_OK; // success! } while (false); } catch (_com_error& err) { hr = err.Error(); ASSERT (false && "Caught _com_error"); } } return (hr); } //############################################################################ //############################################################################ // // Implementation of class CConsoleTaskpadList // //############################################################################ //############################################################################ /*+-------------------------------------------------------------------------* * * CConsoleTaskpadList::ScGetTaskpadList * * PURPOSE: Returns the list of all taskpads that are appropriate for the current node. * * PARAMETERS: * CNode * pNode : * CConsoleTaskpadFilteredList & filteredList : [OUT]: The list of taskpads * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CConsoleTaskpadList::ScGetTaskpadList(CNode *pNode, CConsoleTaskpadFilteredList &filteredList) { DECLARE_SC(sc, TEXT("CConsoleTaskpadList::ScGetTaskpadList")); sc = ScCheckPointers(pNode); if(sc) return sc; // 1. add all built- in taskpads for(iterator iter = begin(); iter != end(); ++iter) { CConsoleTaskpad *pConsoleTaskpad = &*iter; if(pConsoleTaskpad->IsValid(pNode)) { filteredList.push_back(pConsoleTaskpad); } } return sc; } HRESULT CConsoleTaskpadList::ReadSerialObject (IStream &stm, UINT nVersion) { HRESULT hr = S_FALSE; // assume unknown version clear(); if(nVersion == 1) { try { DWORD cItems; stm >> cItems; for(int i=0; i< cItems; i++) { CConsoleTaskpad taskpad; hr = taskpad.Read(stm); BREAK_ON_FAIL (hr); push_back(taskpad); } } catch (_com_error& err) { hr = err.Error(); ASSERT (false && "Caught _com_error"); } } return hr; } //############################################################################ //############################################################################ // // Implementation of class CDefaultTaskpadList // //############################################################################ //############################################################################ HRESULT CDefaultTaskpadList::ReadSerialObject (IStream &stm, UINT nVersion) { HRESULT hr = S_FALSE; // assume unknown version clear(); if(nVersion == 1) { try { /* * TODO: investigate using template operator>> for a map (stgio.h) */ DWORD cItems; stm >> cItems; for(int i=0; i< cItems; i++) { GUID guidNodetype, guidTaskpad; stm >> guidNodetype; stm >> guidTaskpad; operator[](guidNodetype) = guidTaskpad; } hr = S_OK; } catch (_com_error& err) { hr = err.Error(); ASSERT (false && "Caught _com_error"); } } return hr; }