Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3763 lines
128 KiB

//------------------------------------------------------------------------------
// icmdtgt.cpp
// Copyright (c)1997-1999 Microsoft Corporation, All Rights Reserved
//
// Author
// bash
//
// History
// 7-19-97 created (bash)
//
// Implementation of IOleCommandTarget
//
//------------------------------------------------------------------------------
#include "stdafx.h"
#include <mshtmcid.h>
#include <designer.h>
//#include "mfcincl.h"
#include "triedit.h"
#include "document.h"
#include "triedcid.h" //TriEdit Command IDs here.
#include "dispatch.h"
#include "undo.h"
#define CMDSTATE_NOTSUPPORTED 0
#define CMDSTATE_DISABLED OLECMDF_SUPPORTED
#define CMDSTATE_UP (OLECMDF_SUPPORTED | OLECMDF_ENABLED)
#define CMDSTATE_DOWN (OLECMDF_SUPPORTED | OLECMDF_ENABLED | OLECMDF_LATCHED)
#define CMDSTATE_NINCHED (OLECMDF_SUPPORTED | OLECMDF_ENABLED | OLECMDF_NINCHED)
// Mapping from TriEdit to Trident commands
typedef struct {
ULONG cmdTriEdit;
ULONG cmdTrident;
} CMDMAP;
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::MapTriEditCommand
//
// Map the given TriEdit IDM to the equivalent Trident IDM.
//
// Return:
// Mapped command under *pCmdTrident and S_OK for a valid command.
// E_FAIL for an invalid command.
//
HRESULT CTriEditDocument::MapTriEditCommand(ULONG cmdTriEdit, ULONG *pCmdTrident)
{
static CMDMAP rgCmdMap[] = {
{ IDM_TRIED_ACTIVATEACTIVEXCONTROLS, IDM_NOACTIVATENORMALOLECONTROLS },
{ IDM_TRIED_ACTIVATEAPPLETS, IDM_NOACTIVATEJAVAAPPLETS },
{ IDM_TRIED_ACTIVATEDTCS, IDM_NOACTIVATEDESIGNTIMECONTROLS },
{ IDM_TRIED_BACKCOLOR, IDM_BACKCOLOR },
{ IDM_TRIED_BLOCKFMT, IDM_BLOCKFMT },
{ IDM_TRIED_BOLD, IDM_BOLD },
{ IDM_TRIED_BROWSEMODE, IDM_BROWSEMODE },
{ IDM_TRIED_COPY, IDM_COPY },
{ IDM_TRIED_CUT, IDM_CUT },
{ IDM_TRIED_DELETE, IDM_DELETE },
{ IDM_TRIED_EDITMODE, IDM_EDITMODE },
{ IDM_TRIED_FIND, IDM_FIND },
{ IDM_TRIED_FONT, IDM_FONT },
{ IDM_TRIED_FONTNAME, IDM_FONTNAME },
{ IDM_TRIED_FONTSIZE, IDM_FONTSIZE },
{ IDM_TRIED_FORECOLOR, IDM_FORECOLOR },
{ IDM_TRIED_GETBLOCKFMTS, IDM_GETBLOCKFMTS },
{ IDM_TRIED_HYPERLINK, IDM_HYPERLINK },
{ IDM_TRIED_IMAGE, IDM_IMAGE },
{ IDM_TRIED_INDENT, IDM_INDENT },
{ IDM_TRIED_ITALIC, IDM_ITALIC },
{ IDM_TRIED_JUSTIFYCENTER, IDM_JUSTIFYCENTER },
{ IDM_TRIED_JUSTIFYLEFT, IDM_JUSTIFYLEFT },
{ IDM_TRIED_JUSTIFYRIGHT, IDM_JUSTIFYRIGHT },
{ IDM_TRIED_ORDERLIST, IDM_ORDERLIST },
{ IDM_TRIED_OUTDENT, IDM_OUTDENT },
{ IDM_TRIED_PASTE, IDM_PASTE },
{ IDM_TRIED_PRINT, IDM_PRINT },
{ IDM_TRIED_REDO, IDM_REDO },
{ IDM_TRIED_REMOVEFORMAT, IDM_REMOVEFORMAT },
{ IDM_TRIED_SELECTALL, IDM_SELECTALL },
{ IDM_TRIED_SHOWBORDERS, IDM_SHOWZEROBORDERATDESIGNTIME },
{ IDM_TRIED_SHOWDETAILS, IDM_SHOWALLTAGS },
{ IDM_TRIED_UNDERLINE, IDM_UNDERLINE },
{ IDM_TRIED_UNDO, IDM_UNDO },
{ IDM_TRIED_UNLINK, IDM_UNLINK },
{ IDM_TRIED_UNORDERLIST, IDM_UNORDERLIST }
};
if (NULL == pCmdTrident)
return E_POINTER;
for (int i=0; i < sizeof(rgCmdMap)/sizeof(CMDMAP); ++i)
{
if (cmdTriEdit == rgCmdMap[i].cmdTriEdit)
{
*pCmdTrident = rgCmdMap[i].cmdTrident;
return S_OK;
}
}
return E_FAIL;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::SetUpDefaults
//
// Set Trident flags to the TriEdit default values:
//
// IDM_PRESERVEUNDOALWAYS On
// IDM_NOFIXUPURLSONPASTE On
// IDM_NOACTIVATEDESIGNTIMECONTROLS Off
// IDM_NOACTIVATEJAVAAPPLETS On
// IDM_NOACTIVATENORMALOLECONTROLS On
//
//
// No return value.
void CTriEditDocument::SetUpDefaults()
{
VARIANT var;
// Turn on Trident's preserve undo flag for setting properties
V_VT(&var) = VT_BOOL;
V_BOOL(&var) = TRUE;
m_pCmdTgtTrident->Exec(&CMDSETID_Forms3,
6049, // IDM_PRESERVEUNDOALWAYS
OLECMDEXECOPT_DONTPROMPTUSER,
&var,
NULL);
// Turn on Trident's url fixup flag for paste and drag-drop
V_VT(&var) = VT_BOOL;
V_BOOL(&var) = TRUE;
m_pCmdTgtTrident->Exec(&CMDSETID_Forms3,
2335, // IDM_NOFIXUPURLSONPASTE
OLECMDEXECOPT_DONTPROMPTUSER,
&var,
NULL);
// Set up defaults for Activating DTCs but not Applets or other ActiveX Controls
V_VT(&var) = VT_BOOL;
V_BOOL(&var) = FALSE;
m_pCmdTgtTrident->Exec(&CMDSETID_Forms3,
IDM_NOACTIVATEDESIGNTIMECONTROLS,
OLECMDEXECOPT_DONTPROMPTUSER,
&var,
NULL);
V_VT(&var) = VT_BOOL;
V_BOOL(&var) = TRUE;
m_pCmdTgtTrident->Exec(&CMDSETID_Forms3,
IDM_NOACTIVATEJAVAAPPLETS,
OLECMDEXECOPT_DONTPROMPTUSER,
&var,
NULL);
V_VT(&var) = VT_BOOL;
V_BOOL(&var) = TRUE;
m_pCmdTgtTrident->Exec(&CMDSETID_Forms3,
IDM_NOACTIVATENORMALOLECONTROLS,
OLECMDEXECOPT_DONTPROMPTUSER,
&var,
NULL);
}
///////////////////////////////////////////////////////////////////////////////
//
//
// CTriEditDocument::SetUpGlyphTable
//
// Load the glyphs from the DLL and install them in Trident's table. No return
// value.
//
void CTriEditDocument::SetUpGlyphTable(BOOL fDetails)
{
VARIANT var;
const int RuleMax = 100; // This needs to be updated if we ever have a long rule
const int PathMax = 256; // For %program files%\common files\microsoft shared\triedit\triedit.dll
int iGlyphTableStart = IDS_GLYPHTABLESTART;
int iGlyphTableEnd = fDetails ? IDS_GLYPHTABLEEND : IDS_GLYPHTABLEFORMEND;
TCHAR szPathName[PathMax];
TCHAR szRule[RuleMax + PathMax];
TCHAR szGlyphTable[(RuleMax + PathMax) * (IDS_GLYPHTABLEEND - IDS_GLYPHTABLESTART + 1)];
TCHAR *pchGlyphTable, *pchTemp;
// Get full path name for triedit.dll
::GetModuleFileName(_Module.GetModuleInstance(),
szPathName,
sizeof(szPathName)
);
// Load glyph table
pchGlyphTable = szGlyphTable;
for (int i = iGlyphTableStart; i <= iGlyphTableEnd; i++)
{
::LoadString(_Module.GetModuleInstance(), i, szRule, RuleMax);
pchTemp = wcsstr(szRule, _T("!"));
if (pchTemp) // else bad rule, ignore
{
*pchTemp = 0;
// Copy upto the "!"
wcscpy(pchGlyphTable, szRule);
pchGlyphTable += wcslen(szRule);
// Append pathname
wcscpy(pchGlyphTable, szPathName);
pchGlyphTable += wcslen(szPathName);
// Skip past "!"
pchTemp = pchTemp + 1;
// Copy remaining characters
wcscpy(pchGlyphTable, pchTemp);
pchGlyphTable += wcslen(pchTemp);
}
}
// First empty the glyph table
m_pCmdTgtTrident->Exec(&CMDSETID_Forms3,
IDM_EMPTYGLYPHTABLE,
OLECMDEXECOPT_DONTPROMPTUSER,
NULL,
NULL);
V_VT(&var) = VT_BSTR;
V_BSTR(&var) = SysAllocString(szGlyphTable);
m_pCmdTgtTrident->Exec(&CMDSETID_Forms3,
IDM_ADDTOGLYPHTABLE,
OLECMDEXECOPT_DONTPROMPTUSER,
&var,
NULL);
VariantInit(&var);
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::QueryStatus
//
// Report on the status of the given array of TriEdit and Trident commands.
// Pass Trident commands on to Trident. Fix the Trident return value to
// compensate for some inconsistencies. Return S_OK if all goes well, or
// E_FAIL if not.
//
STDMETHODIMP CTriEditDocument::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds,
OLECMD prgCmds[], OLECMDTEXT *pCmdText)
{
OLECMD *pCmd;
INT c;
HRESULT hr;
if (pguidCmdGroup && IsEqualGUID((const GUID&)*pguidCmdGroup, GUID_TriEditCommandGroup))
{
// Loop through each command in the ary, setting the status of each.
for (pCmd = prgCmds, c = cCmds; --c >= 0; pCmd++)
{
// Assume this is a valid command and set default command status to DISABLED.
// The state will get reset to UP, DOWN or NOTSUPPORTED in the switch statement below.
pCmd->cmdf = CMDSTATE_DISABLED;
switch(pCmd->cmdID)
{
case IDM_TRIED_IS_1D_ELEMENT:
case IDM_TRIED_IS_2D_ELEMENT:
{
if (SUCCEEDED(GetElement()) && m_pihtmlElement)
{
pCmd->cmdf = CMDSTATE_UP;
}
break;
}
case IDM_TRIED_SET_ALIGNMENT:
{
pCmd->cmdf = CMDSTATE_UP;
break;
}
case IDM_TRIED_LOCK_ELEMENT:
{
if (SUCCEEDED(GetElement()) && m_pihtmlElement)
{
BOOL f2d=FALSE;
if (SUCCEEDED(Is2DElement(m_pihtmlElement, &f2d)) && f2d)
{
BOOL fLocked=FALSE;
pCmd->cmdf =
(SUCCEEDED(IsLocked(m_pihtmlElement, &fLocked)) && fLocked)
? CMDSTATE_DOWN : CMDSTATE_UP;
}
}
break;
}
case IDM_TRIED_CONSTRAIN:
{
pCmd->cmdf = (m_fConstrain) ? CMDSTATE_DOWN : CMDSTATE_UP;
break;
}
case IDM_TRIED_SEND_TO_BACK:
case IDM_TRIED_SEND_TO_FRONT:
case IDM_TRIED_SEND_BACKWARD:
case IDM_TRIED_SEND_FORWARD:
case IDM_TRIED_SEND_BEHIND_1D:
case IDM_TRIED_SEND_FRONT_1D:
{
if (SUCCEEDED(GetElement()) && m_pihtmlElement)
{
BOOL f2d=FALSE;
if (SUCCEEDED(Is2DElement(m_pihtmlElement, &f2d)) && f2d)
{
pCmd->cmdf = CMDSTATE_UP;
}
}
break;
}
case IDM_TRIED_NUDGE_ELEMENT:
{
BOOL f2d = FALSE;
if (SUCCEEDED(GetElement()) && m_pihtmlElement
&& SUCCEEDED(Is2DElement(m_pihtmlElement, &f2d)) && f2d)
{
BOOL fLock = FALSE;
if (!(SUCCEEDED(IsLocked(m_pihtmlElement, &fLock)) && fLock))
pCmd->cmdf = CMDSTATE_UP;
}
break;
}
case IDM_TRIED_MAKE_ABSOLUTE:
{
if (SUCCEEDED(GetElement()) && m_pihtmlElement)
{
BOOL f2d = FALSE;
if (SUCCEEDED(IsElementDTC(m_pihtmlElement)))
break;
if (SUCCEEDED(Is2DElement(m_pihtmlElement, &f2d)))
{
BOOL f2dCapable=FALSE;
if ( f2d )
{
pCmd->cmdf = CMDSTATE_DOWN;
}
else if (SUCCEEDED(Is2DCapable(m_pihtmlElement, &f2dCapable)) && f2dCapable)
{
pCmd->cmdf = CMDSTATE_UP;
}
}
}
break;
}
case IDM_TRIED_SET_2D_DROP_MODE:
{
pCmd->cmdf = (m_f2dDropMode) ? CMDSTATE_DOWN : CMDSTATE_UP;
break;
}
case IDM_TRIED_INSERTROW:
case IDM_TRIED_DELETEROWS:
case IDM_TRIED_INSERTCELL:
case IDM_TRIED_DELETECELLS:
case IDM_TRIED_INSERTCOL:
{
pCmd->cmdf = (IsSelectionInTable() == S_OK && GetSelectionTypeInTable() != -1)? CMDSTATE_UP : CMDSTATE_DISABLED;
break;
}
case IDM_TRIED_MERGECELLS:
{
ULONG grf = IsSelectionInTable() == S_OK ? GetSelectionTypeInTable() : 0;
pCmd->cmdf = ( (grf != -1) && (!(grf & grfSelectOneCell) && (grf & (grfInSingleRow|grpSelectEntireRow)))) ? CMDSTATE_UP : CMDSTATE_DISABLED;
break;
}
case IDM_TRIED_SPLITCELL:
{
ULONG grf = IsSelectionInTable() == S_OK ? GetSelectionTypeInTable() : 0;
pCmd->cmdf = ((grf != -1) && (grf & grfSelectOneCell)) ? CMDSTATE_UP : CMDSTATE_DISABLED;
break;
}
case IDM_TRIED_DELETECOLS:
{
ULONG grf = IsSelectionInTable() == S_OK ? GetSelectionTypeInTable() : 0;
pCmd->cmdf = ((grf != -1) && (grf & grfInSingleRow)) ? CMDSTATE_UP : CMDSTATE_DISABLED;
break;
}
case IDM_TRIED_INSERTTABLE:
{
pCmd->cmdf = FEnableInsertTable() ? CMDSTATE_UP : CMDSTATE_DISABLED;
break;
}
case IDM_TRIED_DOVERB:
{
if (SUCCEEDED(GetElement()) && m_pihtmlElement && SUCCEEDED(DoVerb(NULL, TRUE)))
pCmd->cmdf = CMDSTATE_UP;
break;
}
case IDM_TRIED_ACTIVATEACTIVEXCONTROLS:
case IDM_TRIED_ACTIVATEAPPLETS:
case IDM_TRIED_ACTIVATEDTCS:
case IDM_TRIED_BACKCOLOR:
case IDM_TRIED_BLOCKFMT:
case IDM_TRIED_BOLD:
case IDM_TRIED_BROWSEMODE:
case IDM_TRIED_COPY:
case IDM_TRIED_CUT:
case IDM_TRIED_DELETE:
case IDM_TRIED_EDITMODE:
case IDM_TRIED_FIND:
case IDM_TRIED_FONT:
case IDM_TRIED_FONTNAME:
case IDM_TRIED_FONTSIZE:
case IDM_TRIED_FORECOLOR:
case IDM_TRIED_GETBLOCKFMTS:
case IDM_TRIED_HYPERLINK:
case IDM_TRIED_IMAGE:
case IDM_TRIED_INDENT:
case IDM_TRIED_ITALIC:
case IDM_TRIED_JUSTIFYCENTER:
case IDM_TRIED_JUSTIFYLEFT:
case IDM_TRIED_JUSTIFYRIGHT:
case IDM_TRIED_ORDERLIST:
case IDM_TRIED_OUTDENT:
case IDM_TRIED_PASTE:
case IDM_TRIED_PRINT:
case IDM_TRIED_REDO:
case IDM_TRIED_REMOVEFORMAT:
case IDM_TRIED_SELECTALL:
case IDM_TRIED_SHOWBORDERS:
case IDM_TRIED_SHOWDETAILS:
case IDM_TRIED_UNDERLINE:
case IDM_TRIED_UNDO:
case IDM_TRIED_UNLINK:
case IDM_TRIED_UNORDERLIST:
{
// We will return E_UNEXPECTED if Trident's command target is not available
hr = E_UNEXPECTED;
_ASSERTE(m_pCmdTgtTrident);
if (m_pCmdTgtTrident)
{
OLECMD olecmd;
olecmd.cmdf = pCmd->cmdf;
if (SUCCEEDED(MapTriEditCommand(pCmd->cmdID, &olecmd.cmdID)))
{
hr = m_pCmdTgtTrident->QueryStatus(&CMDSETID_Forms3, 1, &olecmd, pCmdText);
}
pCmd->cmdf = olecmd.cmdf;
}
if (FAILED(hr))
return hr;
// Trident returns NOTSUPPORTED sometimes when they really mean DISABLED, so we fix this up here.
if (pCmd->cmdf == CMDSTATE_NOTSUPPORTED)
pCmd->cmdf = CMDSTATE_DISABLED;
// Trident returns CMDSTATE_DISABLED for IDM_TRIED_GETBLOCKFMTS but this command should never be disabled
if (pCmd->cmdID == IDM_TRIED_GETBLOCKFMTS)
pCmd->cmdf = CMDSTATE_UP;
// Trident bug: Trident returns the wrong value for IDM_TRIED_SHOWBORDERS,
// IDM_TRIED_SHOWDETAILS and the IDM_TRIED_ACTIVATE* commands, so we fix
// them up here. We don't have code for IDM_TRIED_ACTIVATE* since the logic
// of the Trident commands is actually reverse in these cases.
if (pCmd->cmdID == IDM_TRIED_SHOWBORDERS ||
pCmd->cmdID == IDM_TRIED_SHOWDETAILS)
{
if (pCmd->cmdf == CMDSTATE_UP)
pCmd->cmdf = CMDSTATE_DOWN;
else if (pCmd->cmdf == CMDSTATE_DOWN)
pCmd->cmdf = CMDSTATE_UP;
}
break;
}
default:
{
pCmd->cmdf = CMDSTATE_NOTSUPPORTED;
break;
}
} // switch
} // for
return S_OK;
}
else if (m_pCmdTgtTrident)
{
hr = m_pCmdTgtTrident->QueryStatus(pguidCmdGroup, cCmds, prgCmds, pCmdText);
if (hr != S_OK)
return hr;
// Loop through each command in the ary, fixing up the status of each.
for (pCmd = prgCmds, c = cCmds; --c >= 0; pCmd++)
{
// Trident returns NOTSUPPORTED sometimes when they really mean DISABLED.
if (pCmd->cmdf == CMDSTATE_NOTSUPPORTED)
pCmd->cmdf = CMDSTATE_DISABLED;
if (pguidCmdGroup && IsEqualGUID((const GUID&)*pguidCmdGroup, CMDSETID_Forms3))
{
// Trident returns CMDSTATE_DISABLED for IDM_GETBLOCKFMTS but this command should never be disabled
if (pCmd->cmdID == IDM_GETBLOCKFMTS)
pCmd->cmdf = CMDSTATE_UP;
// Trident bug: Trident returns the wrong value for IDM_SHOWZEROBORDER*,
// IDM_SHOWALLTAGS and the IDM_NOACTIVATE* commands, so we fix
// them up here.
if (pCmd->cmdID == IDM_NOACTIVATENORMALOLECONTROLS ||
pCmd->cmdID == IDM_NOACTIVATEJAVAAPPLETS ||
pCmd->cmdID == IDM_NOACTIVATEDESIGNTIMECONTROLS ||
pCmd->cmdID == IDM_SHOWZEROBORDERATDESIGNTIME ||
pCmd->cmdID == IDM_SHOWALLTAGS)
{
if (pCmd->cmdf == CMDSTATE_UP)
pCmd->cmdf = CMDSTATE_DOWN;
else if (pCmd->cmdf == CMDSTATE_DOWN)
pCmd->cmdf = CMDSTATE_UP;
}
}
}
return S_OK;
}
return E_UNEXPECTED;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::Exec
//
// Perform the given TriEdit or Trident command. Pass Trident commands on to
// Trident for execution. Return S_OK if all goes well or E_FAIL if not.
//
STDMETHODIMP CTriEditDocument::Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut)
{
if (pguidCmdGroup && IsEqualGUID((const GUID&)*pguidCmdGroup, GUID_TriEditCommandGroup) &&
m_pUnkTrident)
{
HRESULT hr = GetElement();
switch(nCmdID)
{
case IDM_TRIED_IS_1D_ELEMENT: //[out,VT_BOOL]
if (pvaOut && m_pihtmlElement &&
SUCCEEDED(VariantChangeType(pvaOut, pvaOut, 0, VT_BOOL)))
{
hr = Is2DElement(m_pihtmlElement, (BOOL*)&pvaOut->boolVal);
_ASSERTE(SUCCEEDED(hr));
if (SUCCEEDED(hr))
{
pvaOut->boolVal = !pvaOut->boolVal;
}
}
break;
case IDM_TRIED_IS_2D_ELEMENT: //[out,VT_BOOL]
if (pvaOut && m_pihtmlElement &&
SUCCEEDED(VariantChangeType(pvaOut, pvaOut, 0, VT_BOOL)))
{
hr = Is2DElement(m_pihtmlElement, (BOOL*)&pvaOut->boolVal);
_ASSERTE(SUCCEEDED(hr));
}
break;
case IDM_TRIED_NUDGE_ELEMENT: //[in,VT_BYREF (VARIANT.byref=LPPOINT)]
{
BOOL fLock = FALSE;
IsLocked(m_pihtmlElement, &fLock);
if (!pvaIn)
hr = E_FAIL;
else if (!fLock && VT_BYREF == pvaIn->vt && pvaIn->byref)
{
hr = NudgeElement(m_pihtmlElement, (LPPOINT)pvaIn->byref);
_ASSERTE(SUCCEEDED(hr));
}
}
break;
case IDM_TRIED_SET_ALIGNMENT: //[in,VT_BYREF (VARIANT.byref=LPPOINT)]
if (!pvaIn)
hr = E_FAIL;
else if (VT_BYREF == pvaIn->vt && pvaIn->byref)
{
hr = SetAlignment((LPPOINT)pvaIn->byref);
_ASSERTE(SUCCEEDED(hr));
}
break;
case IDM_TRIED_LOCK_ELEMENT:
if (m_pihtmlElement)
{
BOOL f2d=FALSE;
BOOL fLocked=TRUE;
if (SUCCEEDED(Is2DElement(m_pihtmlElement, &f2d)) && f2d &&
SUCCEEDED(IsLocked(m_pihtmlElement, &fLocked)))
{
hr = LockElement(m_pihtmlElement, !fLocked);
_ASSERTE(SUCCEEDED(hr));
}
}
break;
case IDM_TRIED_SEND_TO_BACK:
if (m_pihtmlElement)
{
hr = AssignZIndex(m_pihtmlElement, SEND_TO_BACK);
_ASSERTE(SUCCEEDED(hr));
}
break;
case IDM_TRIED_SEND_TO_FRONT:
if (m_pihtmlElement)
{
hr = AssignZIndex(m_pihtmlElement, SEND_TO_FRONT);
_ASSERTE(SUCCEEDED(hr));
}
break;
case IDM_TRIED_SEND_BACKWARD:
if (m_pihtmlElement)
{
hr = AssignZIndex(m_pihtmlElement, SEND_BACKWARD);
_ASSERTE(SUCCEEDED(hr));
}
break;
case IDM_TRIED_SEND_FORWARD:
if (m_pihtmlElement)
{
hr = AssignZIndex(m_pihtmlElement, SEND_FORWARD);
_ASSERTE(SUCCEEDED(hr));
}
break;
case IDM_TRIED_SEND_BEHIND_1D:
if (m_pihtmlElement)
{
hr = AssignZIndex(m_pihtmlElement, SEND_BEHIND_1D);
_ASSERTE(SUCCEEDED(hr));
}
break;
case IDM_TRIED_SEND_FRONT_1D:
if (m_pihtmlElement)
{
hr = AssignZIndex(m_pihtmlElement, SEND_FRONT_1D);
_ASSERTE(SUCCEEDED(hr));
}
break;
case IDM_TRIED_CONSTRAIN:
if (!pvaIn)
hr = E_FAIL;
else if (SUCCEEDED(hr = VariantChangeType(pvaIn, pvaIn, 0, VT_BOOL)))
{
hr = Constrain((BOOL)pvaIn->boolVal);
}
break;
case IDM_TRIED_SET_2D_DROP_MODE:
if (!pvaIn)
hr = E_FAIL;
else if (SUCCEEDED(hr = VariantChangeType(pvaIn, pvaIn, 0, VT_BOOL)))
{
m_f2dDropMode = pvaIn->boolVal;
}
break;
case IDM_TRIED_INSERTROW:
hr = InsertTableRow();
break;
case IDM_TRIED_INSERTCOL:
hr = InsertTableCol();
break;
case IDM_TRIED_INSERTCELL:
hr = InsertTableCell();
break;
case IDM_TRIED_DELETEROWS:
hr = DeleteTableRows();
break;
case IDM_TRIED_DELETECOLS:
hr = DeleteTableCols();
break;
case IDM_TRIED_DELETECELLS:
hr = DeleteTableCells();
break;
case IDM_TRIED_MERGECELLS:
hr = MergeTableCells();
break;
case IDM_TRIED_SPLITCELL:
hr = SplitTableCell();
break;
case IDM_TRIED_INSERTTABLE:
hr = InsertTable(pvaIn);
break;
case IDM_TRIED_DOVERB:
if (m_pihtmlElement)
hr = DoVerb(pvaIn, FALSE);
else
hr = E_FAIL;
break;
case IDM_TRIED_MAKE_ABSOLUTE:
if (m_pihtmlElement)
{
BOOL f2d = FALSE;
hr = Is2DElement(m_pihtmlElement, &f2d);
if (SUCCEEDED(hr))
{
BOOL f2dCapable=FALSE;
if ( f2d )
{
hr = Make1DElement(m_pihtmlElement);
_ASSERTE(SUCCEEDED(hr));
}
else if (SUCCEEDED(Is2DCapable(m_pihtmlElement, &f2dCapable)) && f2dCapable)
{
hr = Make2DElement(m_pihtmlElement);
_ASSERTE(SUCCEEDED(hr));
}
}
}
break;
case IDM_TRIED_ACTIVATEACTIVEXCONTROLS:
case IDM_TRIED_ACTIVATEAPPLETS:
case IDM_TRIED_ACTIVATEDTCS:
case IDM_TRIED_BACKCOLOR:
case IDM_TRIED_BLOCKFMT:
case IDM_TRIED_BOLD:
case IDM_TRIED_BROWSEMODE:
case IDM_TRIED_COPY:
case IDM_TRIED_CUT:
case IDM_TRIED_DELETE:
case IDM_TRIED_EDITMODE:
case IDM_TRIED_FIND:
case IDM_TRIED_FONT:
case IDM_TRIED_FONTNAME:
case IDM_TRIED_FONTSIZE:
case IDM_TRIED_FORECOLOR:
case IDM_TRIED_GETBLOCKFMTS:
case IDM_TRIED_HYPERLINK:
case IDM_TRIED_IMAGE:
case IDM_TRIED_INDENT:
case IDM_TRIED_ITALIC:
case IDM_TRIED_JUSTIFYCENTER:
case IDM_TRIED_JUSTIFYLEFT:
case IDM_TRIED_JUSTIFYRIGHT:
case IDM_TRIED_ORDERLIST:
case IDM_TRIED_OUTDENT:
case IDM_TRIED_PASTE:
case IDM_TRIED_PRINT:
case IDM_TRIED_REDO:
case IDM_TRIED_REMOVEFORMAT:
case IDM_TRIED_SELECTALL:
case IDM_TRIED_SHOWBORDERS:
case IDM_TRIED_SHOWDETAILS:
case IDM_TRIED_UNDERLINE:
case IDM_TRIED_UNDO:
case IDM_TRIED_UNLINK:
case IDM_TRIED_UNORDERLIST:
{
ULONG cmdTrident;
VARIANT varColor;
// We will return E_FAIL if Trident's command target is not available
hr = E_FAIL;
_ASSERTE(m_pCmdTgtTrident);
if (m_pCmdTgtTrident && (SUCCEEDED(MapTriEditCommand(nCmdID, &cmdTrident))))
{
if (nCmdID == IDM_TRIED_ACTIVATEACTIVEXCONTROLS ||
nCmdID == IDM_TRIED_ACTIVATEAPPLETS ||
nCmdID == IDM_TRIED_ACTIVATEDTCS)
{
if (pvaIn && pvaIn->vt == VT_BOOL)
pvaIn->boolVal = !pvaIn->boolVal;
}
// Trident bug: When you exec the forecolor, fontname or fontsize command, they also change the backcolor,
// so we apply a workaround here. The workaround is to save the old backcolor and exec it later.
if (pvaIn && (nCmdID == IDM_TRIED_FORECOLOR || nCmdID == IDM_TRIED_FONTNAME || nCmdID == IDM_TRIED_FONTSIZE))
{
HRESULT hrT;
VariantInit(&varColor);
V_VT(&varColor) = VT_I4;
hrT = m_pCmdTgtTrident->Exec(&CMDSETID_Forms3, IDM_BACKCOLOR, OLECMDEXECOPT_DONTPROMPTUSER, NULL, &varColor);
_ASSERTE(SUCCEEDED(hrT));
}
// Trident bug: When you exec the block format command with "Normal", they don't remove OL and UL tags
if (pvaIn && nCmdID == IDM_TRIED_BLOCKFMT && pvaIn->vt == VT_BSTR && (_wcsicmp(pvaIn->bstrVal, L"Normal") == 0))
{
OLECMD olecmd;
olecmd.cmdID = IDM_ORDERLIST;
olecmd.cmdf = CMDSTATE_NOTSUPPORTED;
if (S_OK == m_pCmdTgtTrident->QueryStatus(&CMDSETID_Forms3, 1, &olecmd, NULL) && olecmd.cmdf == CMDSTATE_DOWN)
m_pCmdTgtTrident->Exec(&CMDSETID_Forms3, IDM_ORDERLIST, OLECMDEXECOPT_DONTPROMPTUSER, NULL, NULL);
olecmd.cmdID = IDM_UNORDERLIST;
olecmd.cmdf = CMDSTATE_NOTSUPPORTED;
if (S_OK == m_pCmdTgtTrident->QueryStatus(&CMDSETID_Forms3, 1, &olecmd, NULL) && olecmd.cmdf == CMDSTATE_DOWN)
m_pCmdTgtTrident->Exec(&CMDSETID_Forms3, IDM_UNORDERLIST, OLECMDEXECOPT_DONTPROMPTUSER, NULL, NULL);
}
hr = m_pCmdTgtTrident->Exec(&CMDSETID_Forms3, cmdTrident, nCmdExecOpt, pvaIn, pvaOut);
if (pvaIn && (nCmdID == IDM_TRIED_FORECOLOR || nCmdID == IDM_TRIED_FONTNAME || nCmdID == IDM_TRIED_FONTSIZE))
{
HRESULT hrT;
hrT = m_pCmdTgtTrident->Exec(&CMDSETID_Forms3, IDM_BACKCOLOR, OLECMDEXECOPT_DONTPROMPTUSER, &varColor, NULL);
_ASSERTE(SUCCEEDED(hrT));
}
else if (nCmdID == IDM_TRIED_SHOWDETAILS && pvaIn && pvaIn->vt == VT_BOOL)
{
SetUpGlyphTable(pvaIn->boolVal);
}
// Trident bug: They enable the justify commands but not actually support them.
// We workaround this by returning S_OK for these no matter what Trident returns.
if (nCmdID == IDM_TRIED_JUSTIFYLEFT || nCmdID == IDM_TRIED_JUSTIFYCENTER || nCmdID == IDM_TRIED_JUSTIFYRIGHT)
hr = S_OK;
}
break;
}
default:
hr = E_FAIL;
break;
}
if (pvaIn)
VariantClear(pvaIn);
// We shouldn't return any unexpected error codes here, so return E_FAIL
if (FAILED(hr))
hr = E_FAIL;
return hr;
}
else if (m_pCmdTgtTrident)
{
HRESULT hr;
BOOL fTridentCmdSet;
VARIANT varColor;
fTridentCmdSet = pguidCmdGroup && IsEqualGUID((const GUID&)*pguidCmdGroup, CMDSETID_Forms3);
#ifdef NEEDED
if (fTridentCmdSet)
{
if (nCmdID == IDM_PARSECOMPLETE)
OnObjectModelComplete();
return S_OK;
}
#endif //NEEDED
// Trident bug: When you exec the forecolor, fontname or fontsize command, they also change the backcolor,
// so we apply a workaround here. The workaround is to save the old backcolor and exec it later.
if (pvaIn && fTridentCmdSet && (nCmdID == IDM_FORECOLOR || nCmdID == IDM_FONTNAME || nCmdID == IDM_FONTSIZE))
{
HRESULT hrT;
VariantInit(&varColor);
V_VT(&varColor) = VT_I4;
hrT = m_pCmdTgtTrident->Exec(pguidCmdGroup, IDM_BACKCOLOR, OLECMDEXECOPT_DONTPROMPTUSER, NULL, &varColor);
_ASSERTE(SUCCEEDED(hrT));
}
// Trident bug: When you exec the block format command with "Normal", they don't remove OL and UL tags
if (pvaIn && fTridentCmdSet && nCmdID == IDM_BLOCKFMT && pvaIn->vt == VT_BSTR && (_wcsicmp(pvaIn->bstrVal, L"Normal") == 0))
{
OLECMD olecmd;
olecmd.cmdID = IDM_ORDERLIST;
olecmd.cmdf = CMDSTATE_NOTSUPPORTED;
if (S_OK == m_pCmdTgtTrident->QueryStatus(&CMDSETID_Forms3, 1, &olecmd, NULL) && olecmd.cmdf == CMDSTATE_DOWN)
m_pCmdTgtTrident->Exec(&CMDSETID_Forms3, IDM_ORDERLIST, OLECMDEXECOPT_DONTPROMPTUSER, NULL, NULL);
olecmd.cmdID = IDM_UNORDERLIST;
olecmd.cmdf = CMDSTATE_NOTSUPPORTED;
if (S_OK == m_pCmdTgtTrident->QueryStatus(&CMDSETID_Forms3, 1, &olecmd, NULL) && olecmd.cmdf == CMDSTATE_DOWN)
m_pCmdTgtTrident->Exec(&CMDSETID_Forms3, IDM_UNORDERLIST, OLECMDEXECOPT_DONTPROMPTUSER, NULL, NULL);
}
hr = m_pCmdTgtTrident->Exec(pguidCmdGroup, nCmdID, nCmdExecOpt, pvaIn, pvaOut);
if (pvaIn && fTridentCmdSet && (nCmdID == IDM_FORECOLOR || nCmdID == IDM_FONTNAME || nCmdID == IDM_FONTSIZE))
{
HRESULT hrT;
hrT = m_pCmdTgtTrident->Exec(pguidCmdGroup, IDM_BACKCOLOR, OLECMDEXECOPT_DONTPROMPTUSER, &varColor, NULL);
_ASSERTE(SUCCEEDED(hrT));
}
else if ((nCmdID == IDM_SHOWALLTAGS || nCmdID == IDM_SHOWMISCTAGS) && pvaIn && pvaIn->vt == VT_BOOL)
{
SetUpGlyphTable(pvaIn->boolVal);
}
// Trident bug: They enable the justify commands but not actually support them.
// We workaround this by returning S_OK for these no matter what Trident returns.
if (fTridentCmdSet && (nCmdID == IDM_JUSTIFYLEFT || nCmdID == IDM_JUSTIFYCENTER || nCmdID == IDM_JUSTIFYRIGHT))
hr = S_OK;
return hr;
}
return E_UNEXPECTED;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::Is2DElement
//
// Test the given HTML element to ascertain if it is 2D positioned or not.
// Return:
// S_OK and *pf2D = TRUE if the element is 2D positioned.
// S_OK and *pf2D = FALSE if the element is not 2D positioned.
//
HRESULT CTriEditDocument::Is2DElement(IHTMLElement* pihtmlElement, BOOL* pf2D)
{
IHTMLStyle* pihtmlStyle = NULL;
BSTR bstrPosition = NULL;
BOOL f2DCapable;
_ASSERTE(pihtmlElement);
_ASSERTE(pf2D);
*pf2D = FALSE;
if (SUCCEEDED(Is2DCapable(pihtmlElement, &f2DCapable)))
{
if (f2DCapable && SUCCEEDED(pihtmlElement->get_style(&pihtmlStyle)))
{
_ASSERTE(pihtmlStyle);
if (SUCCEEDED(pihtmlStyle->get_position(&bstrPosition)))
{
if (bstrPosition)
{
*pf2D = (_wcsicmp(bstrPosition, L"absolute") == 0);
SysFreeString(bstrPosition);
}
SAFERELEASE(pihtmlStyle);
}
}
}
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEDitDocument::NudgeElement
//
// Move the given HTML element (which must be 2D positioned) as indicated
// by pptNudge, further adjusted by the grid spacing in m_ptAlign. Returns
// S_OK if all goes well; E_UNEXPECTED otherwise.
//
HRESULT CTriEditDocument::NudgeElement(IHTMLElement* pihtmlElement, LPPOINT pptNudge)
{
HRESULT hr = E_UNEXPECTED;
IHTMLStyle* pihtmlStyle = NULL;
long x, y;
_ASSERTE(pihtmlElement);
_ASSERTE(pptNudge);
if (pihtmlElement)
{
if (SUCCEEDED(pihtmlElement->get_style(&pihtmlStyle)) &&
pihtmlStyle &&
SUCCEEDED(pihtmlStyle->get_pixelTop(&y)) &&
SUCCEEDED(pihtmlStyle->get_pixelLeft(&x)))
{
if (x == 0 || y == 0)
{
IHTMLElement *pihtmlElementParent = NULL;
RECT rcElement, rcParent;
if (SUCCEEDED(pihtmlElement->get_offsetParent(&pihtmlElementParent))
&& pihtmlElementParent)
{
if (SUCCEEDED(GetElementPosition(pihtmlElement, &rcElement)))
{
::SetRect(&rcParent, 0, 0, 0, 0);
if (SUCCEEDED(GetElementPosition(pihtmlElementParent, &rcParent)))
{
x = rcElement.left - rcParent.left;
y = rcElement.top - rcParent.top;
}
}
pihtmlElementParent->Release();
}
}
x += pptNudge->x;
y += pptNudge->y;
if (pptNudge->x != 0)
{
if (x >= 0)
x -= (x % m_ptAlign.x);
else
x -= (((x % m_ptAlign.x) ? m_ptAlign.x : 0) + (x % m_ptAlign.x));
}
if (pptNudge->y != 0)
{
if (y >= 0)
y -= (y % m_ptAlign.y);
else
y -= (((y % m_ptAlign.y) ? m_ptAlign.y : 0) + (y % m_ptAlign.y));
}
pihtmlStyle->put_pixelTop(y);
pihtmlStyle->put_pixelLeft(x);
return S_OK;
}
}
SAFERELEASE(pihtmlStyle);
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::SetAlignment
//
// Set the TriEdit alignment values as indicated. Return S_OK if all goes
// well; or E_POINTER if a bad pointer is supplied.
//
HRESULT CTriEditDocument::SetAlignment(LPPOINT pptAlign)
{
_ASSERTE(pptAlign);
if (pptAlign)
{
m_ptAlign.x = max(pptAlign->x, 1);
m_ptAlign.y = max(pptAlign->y, 1);
return S_OK;
}
return E_POINTER;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::LockElement
//
// Set or clear the TriEdit design-time locking flag (an expando attribute) as
// indicated by fLock. Return S_OK if all goes well; E_FAIL if not. Note that
// setting the locking flag also sets the top and left attributes if they
// were not already set.
//
HRESULT CTriEditDocument::LockElement(IHTMLElement* pihtmlElement, BOOL fLock)
{
IHTMLStyle* pihtmlStyle=NULL;
HRESULT hr = E_FAIL;
VARIANT var;
VARIANT_BOOL fSuccess = FALSE;
if (pihtmlElement)
{
hr = pihtmlElement->get_style(&pihtmlStyle);
_ASSERTE(SUCCEEDED(hr));
if (SUCCEEDED(hr))
{
_ASSERTE(pihtmlStyle);
if (pihtmlStyle)
{
if(!fLock)
{
hr = pihtmlStyle->removeAttribute(DESIGN_TIME_LOCK, 0, &fSuccess);
_ASSERTE(fSuccess);
}
else
{
// Trident doesn't persist the Design_Time_Lock attribute
// if left, top, width and height properties are not present as part of
// the elements style attribute. Hence as a part of locking the element
// we also assign the top and left styles only if they don't exist.
LONG lTop, lLeft;
pihtmlStyle->get_pixelTop(&lTop);
pihtmlStyle->get_pixelLeft(&lLeft);
if (lTop == 0 || lLeft == 0)
{
IHTMLElement *pihtmlElementParent = NULL;
if (SUCCEEDED(pihtmlElement->get_offsetParent(&pihtmlElementParent))
&& pihtmlElementParent)
{
if (SUCCEEDED(GetElementPosition(pihtmlElement, &m_rcElement)))
{
RECT rcParent;
::SetRect(&rcParent, 0, 0, 0, 0);
if (SUCCEEDED(GetElementPosition(pihtmlElementParent, &rcParent)))
{
m_rcElement.left = m_rcElement.left - rcParent.left;
m_rcElement.top = m_rcElement.top - rcParent.top;
pihtmlStyle->put_pixelTop(m_rcElement.top);
pihtmlStyle->put_pixelLeft(m_rcElement.left);
}
}
pihtmlElementParent->Release();
}
}
VariantInit(&var);
var.vt = VT_BSTR;
var.bstrVal = SysAllocString(L"True");
hr = pihtmlStyle->setAttribute(DESIGN_TIME_LOCK, var, 0);
hr = SUCCEEDED(hr) ? S_OK:E_FAIL;
}
pihtmlStyle->Release();
}
}
if (SUCCEEDED(hr))
{
RECT rcElement;
hr = GetElementPosition(pihtmlElement, &rcElement);
_ASSERTE(SUCCEEDED(hr));
if (SUCCEEDED(hr))
{
InflateRect(&rcElement, ELEMENT_GRAB_SIZE, ELEMENT_GRAB_SIZE);
if( SUCCEEDED(hr = GetTridentWindow()))
{
_ASSERTE(m_hwndTrident);
InvalidateRect(m_hwndTrident,&rcElement, FALSE);
}
}
// Trident doesn't set itself to be dirty, so force the dirty state.
VariantInit(&var);
var.vt = VT_BOOL;
var.boolVal = TRUE;
if (m_pCmdTgtTrident)
m_pCmdTgtTrident->Exec(&CMDSETID_Forms3, IDM_SETDIRTY, 0, &var, NULL);
}
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::IsLocked
//
// Test the given HTML element to ascertain if it is design-time locked or not.
// Return:
// S_OK and *pfLocked = TRUE if the element is design-time locked.
// S_OK and *pfLocked = FALSE if the element is not design-time locked.
//
HRESULT CTriEditDocument::IsLocked(IHTMLElement* pihtmlElement, BOOL* pfLocked)
{
IHTMLStyle* pihtmlStyle=NULL;
BSTR bstrAttributeName = NULL;
HRESULT hr = E_FAIL;
VARIANT var;
VariantInit(&var);
var.vt = VT_BSTR;
var.bstrVal = NULL;
if (pihtmlElement)
{
hr = pihtmlElement->get_style(&pihtmlStyle);
_ASSERTE(SUCCEEDED(hr));
if (SUCCEEDED(hr))
{
_ASSERTE(pihtmlStyle);
if (pihtmlStyle)
{
bstrAttributeName = SysAllocString(DESIGN_TIME_LOCK);
if (bstrAttributeName)
{
hr = pihtmlStyle->getAttribute(bstrAttributeName, 0, &var);
_ASSERTE(SUCCEEDED(hr));
if (var.bstrVal == NULL)
*pfLocked = FALSE;
else
*pfLocked = TRUE;
SysFreeString(bstrAttributeName);
}
pihtmlStyle->Release();
}
}
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
//
// CTriEditDocument::Make1DElement
//
// Set the given HTML element to layout in the flow. As a side effect this
// also removes any design-time lock on the element. Return S_OK if all goes
// well; E_UNEXPECTED otherwise.
//
HRESULT CTriEditDocument::Make1DElement(IHTMLElement* pihtmlElement)
{
IHTMLStyle* pihtmlStyle=NULL;
VARIANT_BOOL fSuccess = FALSE;
VARIANT var;
HRESULT hr;
if (pihtmlElement)
{
pihtmlElement->get_style(&pihtmlStyle);
_ASSERTE(pihtmlStyle);
if (pihtmlStyle)
{
VariantInit(&var);
var.vt = VT_I4;
var.lVal = 0;
hr = pihtmlStyle->put_zIndex(var);
_ASSERTE(SUCCEEDED(hr));
pihtmlStyle->removeAttribute(DESIGN_TIME_LOCK, 0, &fSuccess);
pihtmlStyle->removeAttribute(L"position", 0, &fSuccess);
pihtmlStyle->Release();
}
}
return (fSuccess? S_OK: E_UNEXPECTED);
}
///////////////////////////////////////////////////////////////////////////////
//
//
// CTriEditDocument::Make2DElement
//
// Set the given HTML element to be positioned. Return S_OK if all goes
// well; E_FAIL otherwise.
//
HRESULT CTriEditDocument::Make2DElement(IHTMLElement* pihtmlElement, POINT *ppt)
{
IHTMLElement* pihtmlElementParent = NULL;
IHTMLElementCollection* pihtmlCollection = NULL;
IHTMLElement* pihtmlElementNew = NULL;
IHTMLStyle* pihtmlElementStyle = NULL;
VARIANT var;
LONG lSourceIndex;
HRESULT hr = E_FAIL;
BSTR bstrOuterHtml = NULL;
_ASSERTE(pihtmlElement);
if(!pihtmlElement)
{
return E_FAIL;
}
hr = pihtmlElement->get_style(&pihtmlElementStyle);
_ASSERTE(SUCCEEDED(hr) && pihtmlElementStyle);
if (FAILED(hr) || !pihtmlElementStyle)
{
return E_FAIL;
}
// The reason to save the source index here is that once we call put_outerHTML
// the element is lost, we later use the source index to get back the element from the collection.
// Note that the source index remains the same after put_outerHTML.
hr = pihtmlElement->get_sourceIndex(&lSourceIndex);
_ASSERTE(SUCCEEDED(hr) && (lSourceIndex != -1));
if (lSourceIndex == -1 || FAILED(hr))
{
return E_FAIL;
}
hr = pihtmlElement->get_offsetParent(&pihtmlElementParent);
_ASSERTE(SUCCEEDED(hr) && pihtmlElementParent);
if (SUCCEEDED(hr) && pihtmlElementParent)
{
VariantInit(&var);
var.vt = VT_BSTR;
var.bstrVal = SysAllocString(L"absolute");
hr = pihtmlElementStyle->setAttribute(L"position", var, 1);
if (var.bstrVal)
SysFreeString(var.bstrVal);
_ASSERTE(SUCCEEDED(hr));
if (SUCCEEDED(hr))
{
if (SUCCEEDED(hr = GetElementPosition(pihtmlElement, &m_rcElement)))
{
IHTMLTable* pihtmlTable = NULL;
IHTMLElement* pihtmlElementTemp = NULL, *pihtmlElementPrev = NULL;
RECT rcParent;
BOOL f2d = FALSE;
BOOL fIsIE5AndBeyond = IsIE5OrBetterInstalled();
::SetRect(&rcParent, 0, 0, 0, 0);
pihtmlElementTemp = pihtmlElementParent;
pihtmlElementTemp->AddRef();
// Handle tables specially since the offset parent may have been the TD or the TR
while (pihtmlElementTemp)
{
if (SUCCEEDED(pihtmlElementTemp->QueryInterface(IID_IHTMLTable, (void **)&pihtmlTable)) && pihtmlTable)
break;
pihtmlElementPrev = pihtmlElementTemp;
pihtmlElementPrev->get_offsetParent(&pihtmlElementTemp);
SAFERELEASE(pihtmlElementPrev);
}
// If parent is a 2d element, we need to offset its top and left
if (pihtmlElementTemp && SUCCEEDED(Is2DElement(pihtmlElementTemp, &f2d)) && f2d)
{
GetElementPosition(pihtmlElementTemp, &rcParent);
}
else if (SUCCEEDED(Is2DElement(pihtmlElementParent, &f2d)) && f2d)
{
GetElementPosition(pihtmlElementParent, &rcParent);
}
SAFERELEASE(pihtmlTable);
SAFERELEASE(pihtmlElementTemp);
SAFERELEASE(pihtmlElementPrev);
m_rcElement.left = (ppt ? ppt->x : m_rcElement.left) - rcParent.left;
m_rcElement.top = (ppt ? ppt->y : m_rcElement.top) - rcParent.top;
// We need to call get_outerHTML and put_outerHTML to work around a Trident bug
// We should not really have to call these here, but the element doesn't get
// updated unless we do this.
if (fIsIE5AndBeyond || SUCCEEDED(hr = pihtmlElement->get_outerHTML(&bstrOuterHtml)))
{
if (fIsIE5AndBeyond || SUCCEEDED(hr = pihtmlElement->put_outerHTML(bstrOuterHtml)))
{
hr = GetAllCollection(&pihtmlCollection);
_ASSERTE(SUCCEEDED(hr));
_ASSERTE(pihtmlCollection);
if (SUCCEEDED(hr) && pihtmlCollection)
{
hr = GetCollectionElement(pihtmlCollection, lSourceIndex, &pihtmlElementNew);
_ASSERTE(SUCCEEDED(hr));
_ASSERTE(pihtmlElementNew);
if (SUCCEEDED(hr) && pihtmlElementNew)
{
hr = SelectElement(pihtmlElementNew, pihtmlElementParent);
GetElement(); // to update m_pihtmlElement and friends after the above SelectElement
if (SUCCEEDED(hr))
{
hr = AssignZIndex(pihtmlElementNew, MADE_ABSOLUTE);
_ASSERTE(SUCCEEDED(hr));
if (SUCCEEDED(hr))
{
SAFERELEASE(pihtmlElementStyle);
if (SUCCEEDED(hr = pihtmlElementNew->get_style(&pihtmlElementStyle)))
{
pihtmlElementStyle->put_pixelLeft(m_rcElement.left);
pihtmlElementStyle->put_pixelTop(m_rcElement.top);
VariantInit(&var);
var.vt = VT_BOOL;
var.boolVal = FALSE;
pihtmlElementNew->scrollIntoView(var);
}
}
}
}
}
}
}
}
}
}
if (bstrOuterHtml)
SysFreeString(bstrOuterHtml);
SAFERELEASE(pihtmlElementParent);
SAFERELEASE(pihtmlElementStyle);
SAFERELEASE(pihtmlElementNew);
SAFERELEASE(pihtmlCollection);
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::Constrain
//
// Set the TriEdit constraint flag as indicated by fConstrain. Also, reset
// the constraint direction to CONSTRAIN_NONE. Return S_OK.
HRESULT CTriEditDocument::Constrain(BOOL fConstrain)
{
m_fConstrain = (fConstrain) ? TRUE:FALSE;
m_eDirection = CONSTRAIN_NONE;
return S_OK;
}
typedef struct SELCELLINFO
{
LONG cCellIndex; // cell index in a row
LONG cRowIndex; // which row is this cell in
CComPtr<IDispatch> srpCell; // cell element
CComPtr<IDispatch> srpRow; // row element
CComPtr<IDispatch> srpTable;
} SELCELLINFO;
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::GetTableRowElementAndTableFromCell
//
// Given the IDispatch pointer to an element within a table, return the
// row index in *pindexRow (if pindexRow is not NULL) and/or the
// actual row element in *psrpRow (if psrpRow is not NULL) of the
// element within the table. If psrpTable is not NULL, return the
// table containing the element therein. Return S_OK if all goes well,
// or E_FAIL if something goes wrong.
//
HRESULT CTriEditDocument::GetTableRowElementAndTableFromCell(IDispatch *srpCell, LONG *pindexRow , IDispatch **psrpRow, IDispatch **psrpTable)
{
CComPtr<IDispatch> srpParent,srpElement;
HRESULT hr = E_FAIL;
CComBSTR bstrTag;
_ASSERTE(srpCell != NULL);
if (pindexRow == NULL && psrpRow == NULL)
goto Fail;
srpParent = srpCell;
while (srpParent != NULL)
{
srpElement.Release();
if (FAILED(hr = GetDispatchProperty(srpParent, L"parentElement", VT_DISPATCH, (void**)&srpElement)))
goto Fail;
if (srpElement == NULL)
{
hr = E_FAIL;
goto Fail;
}
bstrTag.Empty();
if (FAILED(hr = GetDispatchProperty(srpElement, L"tagName", VT_BSTR, &bstrTag)))
goto Fail;
if (lstrcmpi(_T("TR"), OLE2T(bstrTag)) == 0)
{
if (psrpRow != NULL)
{
*psrpRow = srpElement;
(*psrpRow)->AddRef();
}
if (pindexRow != NULL)
{
if (FAILED(hr = GetDispatchProperty(srpElement, L"rowIndex", VT_I4, pindexRow)))
goto Fail;
}
break;
}
srpParent = srpElement;
}
if (psrpTable != NULL)
{
srpParent = srpElement;
while (srpParent != NULL)
{
srpElement.Release();
if (FAILED(hr = GetDispatchProperty(srpParent, L"parentElement", VT_DISPATCH, (void**)&srpElement)))
goto Fail;
if (srpElement == NULL)
{
hr = E_FAIL;
goto Fail;
}
bstrTag.Empty();
if (FAILED(hr = GetDispatchProperty(srpElement, L"tagName", VT_BSTR, &bstrTag)))
goto Fail;
if (lstrcmpi(_T("TABLE"), OLE2T(bstrTag)) == 0)
{
if (psrpTable != NULL)
{
*psrpTable = srpElement;
(*psrpTable)->AddRef();
}
break;
}
srpParent = srpElement;
}
}
Fail:
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::FEnableInsertTable
//
// Return TRUE if the Trident selection is within a table and if the selection
// type and location will allow elements to be inserted within the table.
// Return FALSE otherwise.
//
BOOL CTriEditDocument::FEnableInsertTable(void)
{
BOOL fRet = FALSE;
CComPtr<IDispatch> srpRange,srpParent,srpElement;
CComPtr<IHTMLSelectionObject> srpSel;
CComPtr<IHTMLDocument2> srpiHTMLDoc;
CComBSTR bstr;
CComBSTR bstrTag;
if (FAILED(m_pUnkTrident->QueryInterface(IID_IHTMLDocument2, (void**)&srpiHTMLDoc)))
goto Fail;
if (FAILED(srpiHTMLDoc->get_selection(&srpSel)))
goto Fail;
if (FAILED(GetDispatchProperty(srpSel, L"type", VT_BSTR, &bstr)))
goto Fail;
if (lstrcmpi(_T("CONTROL"), OLE2T(bstr)) == 0)
{
return FALSE;
}
if (FAILED(CallDispatchMethod(srpSel, L"createRange", VTS_DISPATCH_RETURN, (void**)&srpRange)))
goto Fail;
if (srpRange == NULL)
goto Fail;
srpParent = srpRange;
while (srpParent != NULL)
{
srpElement.Release();
if (FAILED(GetDispatchProperty(srpParent, L"parentElement", VT_DISPATCH, (void**)&srpElement)))
goto Fail;
if (srpElement == NULL)
break;
bstrTag.Empty();
if (FAILED(GetDispatchProperty(srpElement, L"tagName", VT_BSTR, &bstrTag)))
goto Fail;
if (lstrcmpi(_T("INPUT"), OLE2T(bstrTag)) == 0)
{
return FALSE;
}
srpParent = srpElement;
}
// if the selection is inside a table, make sure only one cell is selected
if (IsSelectionInTable() == S_OK)
{
UINT grf = GetSelectionTypeInTable();
if (grf != -1 && !(grf & grfSelectOneCell))
return FALSE;
}
fRet = TRUE;
Fail:
return fRet;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::IsSelectionInTable
//
// Return S_OK if the Trident selection is within a table. Return
// E_FAIL otherwise.
//
HRESULT CTriEditDocument::IsSelectionInTable(IDispatch **ppTable)
{
HRESULT hr=0;
CComPtr<IHTMLSelectionObject> srpSel;
CComPtr<IDispatch> srpRange,srpParent,srpElement;
CComPtr<IHTMLDocument2> srpiHTMLDoc;
CComBSTR bstrTag;
BOOL fTable= FALSE;
if (FAILED(hr = m_pUnkTrident->QueryInterface(IID_IHTMLDocument2, (void**)&srpiHTMLDoc)))
goto Fail;
if (FAILED(hr = srpiHTMLDoc->get_selection(&srpSel)))
goto Fail;
if (FAILED(hr = CallDispatchMethod(srpSel, L"createRange", VTS_DISPATCH_RETURN, (void**)&srpRange)))
goto Fail;
srpParent = srpRange;
while (srpParent != NULL)
{
srpElement.Release();
if (FAILED(hr = GetDispatchProperty(srpParent, L"parentElement", VT_DISPATCH, (void**)&srpElement)))
goto Fail;
if (srpElement == NULL)
break;
bstrTag.Empty();
if (FAILED(hr = GetDispatchProperty(srpElement, L"tagName", VT_BSTR, &bstrTag)))
goto Fail;
if (lstrcmpi(_T("TABLE"), OLE2T(bstrTag)) == 0)
{
if (ppTable != NULL)
{
*ppTable = srpElement;
(*ppTable)->AddRef();
}
fTable = TRUE;
break;
}
else if (lstrcmpi(_T("CAPTION"), OLE2T(bstrTag)) == 0)
{
fTable = FALSE;
break;
}
srpParent = srpElement;
}
Fail:
return fTable ? S_OK : E_FAIL;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::FillInSelectionCellsInfo
//
// Fill *pSelStart with the information concerning the table cell containing
// the beginning of the Trident selection and *pSelSle with the information
// on the table cell at the end of the selection. Return S_OK if all goes well,
// or E_FAIL otherwise.
HRESULT CTriEditDocument::FillInSelectionCellsInfo(struct SELCELLINFO * pselStart, struct SELCELLINFO *pselEnd)
{
CComPtr<IHTMLDocument2> srpiHTMLDoc;
CComPtr<IHTMLSelectionObject> srpSel;
CComPtr<IHTMLTxtRange> srpRange[2];
CComPtr<IDispatch> srpParent;
CComBSTR bstrText, bstrTag;;
LONG cReturn=0;
HRESULT i=0, hr=0;
LONG cCharSelected=0;
WCHAR *pData = NULL;
BOOL fContain = FALSE;
if (FAILED(hr = IsSelectionInTable()))
goto Fail;
if (FAILED(hr = m_pUnkTrident->QueryInterface(IID_IHTMLDocument2, (void**)&srpiHTMLDoc)))
goto Fail;
if (FAILED(hr = srpiHTMLDoc->get_selection(&srpSel)))
goto Fail;
for (i=0; i<2 ; i++)
{
// BUG 568250. We HAD treated the dispatch like a text range, this now crashes.
CComPtr<IDispatch> srpDisp;
if (FAILED(hr = CallDispatchMethod(srpSel, L"createRange", VTS_DISPATCH_RETURN, (void**)&srpDisp)))
{
goto Fail;
}
else
{
if (FAILED(hr = srpDisp->QueryInterface(&srpRange[i])))
goto Fail;
}
}
bstrText.Empty();
hr = srpRange[0]->get_text(&bstrText);
if (FAILED(hr))
goto Fail;
cCharSelected = bstrText ? ocslen(bstrText) : 0;
pData = (WCHAR *) bstrText;
// VID98 bug 3117: trident use '0x0D' to mark column/row and this char is ignored when
// move range so we need to deduct these characters
while (pData != NULL && *pData !='\0')
{
if (*pData == 0x0D)
cCharSelected--;
pData++;
}
if (pselStart != NULL)
{
hr = srpRange[0]->collapse(TRUE);
if (FAILED(hr))
goto Fail;
srpParent = srpRange[0];
while (srpParent != NULL)
{
pselStart->srpCell.Release();
if (FAILED(hr = GetDispatchProperty(srpParent, L"parentElement", VT_DISPATCH, (void**)&pselStart->srpCell)))
goto Fail;
if (pselStart->srpCell == NULL)
{
hr = E_FAIL;
goto Fail;
}
bstrTag.Empty();
if (FAILED(hr = GetDispatchProperty(pselStart->srpCell, L"tagName", VT_BSTR, &bstrTag)))
goto Fail;
if (lstrcmpi(_T("TD"), OLE2T(bstrTag)) == 0 || lstrcmpi(_T("TH"), OLE2T(bstrTag)) == 0)
{
break;
}
srpParent = pselStart->srpCell;
}
_ASSERTE(pselStart->srpCell != NULL);
if (FAILED(hr = GetDispatchProperty(pselStart->srpCell, L"cellIndex", VT_I4, &pselStart->cCellIndex)))
goto Fail;
pselStart->srpRow.Release();
if (FAILED(hr = GetTableRowElementAndTableFromCell(pselStart->srpCell, &pselStart->cRowIndex, &pselStart->srpRow, &pselStart->srpTable)))
goto Fail;
}
if (pselEnd != NULL)
{
hr = srpRange[1]->collapse(FALSE);
if (FAILED(hr))
goto Fail;
if (cCharSelected != 0)
{
hr = srpRange[1]->moveStart(L"Character", -1, &cReturn);
if (FAILED(hr))
goto Fail;
hr = srpRange[1]->moveEnd(L"Character", -1, &cReturn);
if (FAILED(hr))
goto Fail;
}
srpParent = srpRange[1];
while (srpParent != NULL)
{
pselEnd->srpCell.Release();
if (FAILED(hr = GetDispatchProperty(srpParent, L"parentElement", VT_DISPATCH, (void**)&pselEnd->srpCell)))
goto Fail;
if (pselEnd->srpCell == NULL)
{
hr = E_FAIL;
goto Fail;
}
bstrTag.Empty();
if (FAILED(hr = GetDispatchProperty(pselEnd->srpCell, L"tagName", VT_BSTR, &bstrTag)))
goto Fail;
if (lstrcmpi(_T("TD"), OLE2T(bstrTag)) == 0 || lstrcmpi(_T("TH"), OLE2T(bstrTag)) == 0)
{
break;
}
srpParent = pselEnd->srpCell;
}
_ASSERTE(pselEnd->srpCell != NULL);
if (FAILED(hr = GetDispatchProperty(pselEnd->srpCell, L"cellIndex", VT_I4, &pselEnd->cCellIndex)))
goto Fail;
pselEnd->srpRow.Release();
if (FAILED(hr = GetTableRowElementAndTableFromCell(pselEnd->srpCell, &pselEnd->cRowIndex, &pselEnd->srpRow, &pselEnd->srpTable)))
goto Fail;
}
if (pselEnd != NULL && pselStart != NULL)
{
// VID 98 bug 3116: we need to check if first cell and last cell are in the same table. If they are not
// the row index and cell index we just got do not make sense
if (FAILED(hr = CallDispatchMethod(pselEnd->srpTable, L"contains", VTS_DISPATCH VTS_BOOL_RETURN, pselStart->srpRow, &fContain)))
goto Fail;
if (!fContain)
return E_FAIL;
fContain = FALSE;
if (FAILED(hr = CallDispatchMethod(pselStart->srpTable, L"contains", VTS_DISPATCH VTS_BOOL_RETURN, pselEnd->srpRow, &fContain)))
goto Fail;
if (!fContain)
return E_FAIL;
}
Fail:
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::GetSelectionTypeInTable
//
// Return a set of flags that characterize the current selection. Return
// -1 if something goes wrong. The flags are as follows:
//
// grfInSingleRow Selection is comprised of one or more cells
// within a single row.
//
// grfSelectOneCell Selection is comprised of a single cell.
//
// grpSelectEntireRow Selection is comprised of one or more
// complete rows.
ULONG CTriEditDocument::GetSelectionTypeInTable(void)
{
CComPtr<IDispatch> srpCells;
struct SELCELLINFO selinfo[2]; // 0 is start cell, 1 is end cell
LONG cCells=0;
HRESULT hr=0;
ULONG grf=0;
if (FAILED(hr = FillInSelectionCellsInfo(&selinfo[0], &selinfo[1])))
goto Fail;
if (selinfo[0].cRowIndex == selinfo[1].cRowIndex)
{
grf |= grfInSingleRow;
if (selinfo[0].cCellIndex == selinfo[1].cCellIndex)
grf |= grfSelectOneCell;
}
else
{
grf &= ~grfInSingleRow;
}
if (selinfo[0].cCellIndex != 0)
grf &= ~grpSelectEntireRow;
else
{
srpCells.Release();
if (FAILED(hr = GetDispatchProperty(selinfo[1].srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
goto Fail;
if (FAILED(hr = GetDispatchProperty(srpCells, L"length", VT_I4, &cCells)))
goto Fail;
if (selinfo[1].cCellIndex != cCells-1)
grf &= ~grpSelectEntireRow;
else
grf |= grpSelectEntireRow;
}
Fail:
return FAILED(hr) ? -1 : grf;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::CopyProperty
//
// Copy properties from the pFrom element on to the pTo element. Return S_OK.
//
HRESULT CTriEditDocument::CopyProperty(IDispatch *pFrom, IDispatch *pTo)
{
CComVariant varProp;
CComBSTR bstrProp;
VARIANT_BOOL bProp;
bstrProp.Empty();
if (SUCCEEDED(GetDispatchProperty(pFrom, L"align", VT_BSTR, (void **)&bstrProp)))
{
if (lstrcmpW(bstrProp, L""))
PutDispatchProperty(pTo, L"align", VT_BSTR, bstrProp);
}
bstrProp.Empty();
if (SUCCEEDED(GetDispatchProperty(pFrom, L"vAlign", VT_BSTR, (void **)&bstrProp)))
{
if (lstrcmpW(bstrProp, L""))
PutDispatchProperty(pTo, L"vAlign", VT_BSTR, bstrProp);
}
bstrProp.Empty();
if (SUCCEEDED(GetDispatchProperty(pFrom, L"background", VT_BSTR, (void **)&bstrProp)))
{
if (lstrcmpW(bstrProp, L""))
PutDispatchProperty(pTo, L"background", VT_BSTR, bstrProp);
}
bstrProp.Empty();
if (SUCCEEDED(GetDispatchProperty(pFrom, L"lang", VT_BSTR, (void **)&bstrProp)))
{
if (lstrcmpW(bstrProp, L""))
PutDispatchProperty(pTo, L"lang", VT_BSTR, bstrProp);
}
bstrProp.Empty();
if (SUCCEEDED(GetDispatchProperty(pFrom, L"className", VT_BSTR, (void **)&bstrProp)))
{
if (lstrcmpW(bstrProp, L""))
PutDispatchProperty(pTo, L"className", VT_BSTR, bstrProp);
}
varProp.Clear();
if (SUCCEEDED(GetDispatchProperty(pFrom, L"bgColor", VT_VARIANT, (void **)&varProp)))
PutDispatchProperty(pTo, L"bgColor", VT_VARIANT, varProp);
varProp.Clear();
if (SUCCEEDED(GetDispatchProperty(pFrom, L"borderColor", VT_VARIANT, (void **)&varProp)))
PutDispatchProperty(pTo, L"borderColor", VT_VARIANT, varProp);
varProp.Clear();
if (SUCCEEDED(GetDispatchProperty(pFrom, L"borderColorLight", VT_VARIANT, (void **)&varProp)))
PutDispatchProperty(pTo, L"borderColorLight", VT_VARIANT, varProp);
varProp.Clear();
if (SUCCEEDED(GetDispatchProperty(pFrom, L"borderColorDark", VT_VARIANT, (void **)&varProp)))
PutDispatchProperty(pTo, L"borderColorDark", VT_VARIANT, varProp);
varProp.Clear();
if (SUCCEEDED(GetDispatchProperty(pFrom, L"height", VT_VARIANT, (void **)&varProp)))
PutDispatchProperty(pTo, L"height", VT_VARIANT, varProp);
varProp.Clear();
if (SUCCEEDED(GetDispatchProperty(pFrom, L"width", VT_VARIANT, (void **)&varProp)))
PutDispatchProperty(pTo, L"width", VT_VARIANT, varProp);
if (SUCCEEDED(GetDispatchProperty(pFrom, L"noWrap", VT_BOOL, (void **)&bProp)))
{
#pragma warning(disable: 4310) // cast truncates constant value
if (bProp == VARIANT_TRUE)
#pragma warning(default: 4310) // cast truncates constant value
PutDispatchProperty(pTo, L"noWrap", VT_BOOL, bProp);
}
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::CopyStyle
//
// Copy style properties from style element pFrom on to style element pTo.
// Return S_OK.
//
HRESULT CTriEditDocument::CopyStyle(IDispatch *pFrom, IDispatch *pTo)
{
CComPtr<IDispatch> srpStyleTo, srpStyleFrom;
if (SUCCEEDED(GetDispatchProperty(pFrom, L"style", VT_DISPATCH, (void **)&srpStyleFrom)))
{
if (SUCCEEDED(GetDispatchProperty(pTo, L"style", VT_DISPATCH, (void **)&srpStyleTo)))
{
CComVariant varProp;
CComBSTR bstrProp;
bstrProp.Empty();
if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"backgroundAttachment", VT_BSTR, (void **)&bstrProp)))
{
if (lstrcmpW(bstrProp, L""))
PutDispatchProperty(srpStyleTo, L"backgroundAttachment", VT_BSTR, bstrProp);
}
bstrProp.Empty();
if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"backgroundImage", VT_BSTR, (void **)&bstrProp)))
{
if (lstrcmpW(bstrProp, L""))
PutDispatchProperty(srpStyleTo, L"backgroundImage", VT_BSTR, bstrProp);
}
bstrProp.Empty();
if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"backgroundRepeat", VT_BSTR, (void **)&bstrProp)))
{
if (lstrcmpW(bstrProp, L""))
PutDispatchProperty(srpStyleTo, L"backgroundRepeat", VT_BSTR, bstrProp);
}
bstrProp.Empty();
if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"borderBottom", VT_BSTR, (void **)&bstrProp)))
{
if (lstrcmpW(bstrProp, L""))
PutDispatchProperty(srpStyleTo, L"borderBottom", VT_BSTR, bstrProp);
}
bstrProp.Empty();
if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"borderLeft", VT_BSTR, (void **)&bstrProp)))
{
if (lstrcmpW(bstrProp, L""))
PutDispatchProperty(srpStyleTo, L"borderLeft", VT_BSTR, bstrProp);
}
bstrProp.Empty();
if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"borderTop", VT_BSTR, (void **)&bstrProp)))
{
if (lstrcmpW(bstrProp, L""))
PutDispatchProperty(srpStyleTo, L"borderTop", VT_BSTR, bstrProp);
}
bstrProp.Empty();
if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"borderRight", VT_BSTR, (void **)&bstrProp)))
{
if (lstrcmpW(bstrProp, L""))
PutDispatchProperty(srpStyleTo, L"borderRight", VT_BSTR, bstrProp);
}
bstrProp.Empty();
if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"fontFamily", VT_BSTR, (void **)&bstrProp)))
{
if (lstrcmpW(bstrProp, L""))
PutDispatchProperty(srpStyleTo, L"fontFamily", VT_BSTR, bstrProp);
}
bstrProp.Empty();
if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"fontStyle", VT_BSTR, (void **)&bstrProp)))
{
if (lstrcmpW(bstrProp, L""))
PutDispatchProperty(srpStyleTo, L"fontStyle", VT_BSTR, bstrProp);
}
bstrProp.Empty();
if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"fontVariant", VT_BSTR, (void **)&bstrProp)))
{
if (lstrcmpW(bstrProp, L""))
PutDispatchProperty(srpStyleTo, L"fontVariant", VT_BSTR, bstrProp);
}
bstrProp.Empty();
if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"fontWeight", VT_BSTR, (void **)&bstrProp)))
{
if (lstrcmpW(bstrProp, L""))
PutDispatchProperty(srpStyleTo, L"fontWeight", VT_BSTR, bstrProp);
}
bstrProp.Empty();
if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"textAlign", VT_BSTR, (void **)&bstrProp)))
{
if (lstrcmpW(bstrProp, L""))
PutDispatchProperty(srpStyleTo, L"textAlign", VT_BSTR, bstrProp);
}
bstrProp.Empty();
if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"textTransform", VT_BSTR, (void **)&bstrProp)))
{
if (lstrcmpW(bstrProp, L""))
PutDispatchProperty(srpStyleTo, L"textTransform", VT_BSTR, bstrProp);
}
bstrProp.Empty();
if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"textDecoration", VT_BSTR, (void **)&bstrProp)))
{
if (lstrcmpW(bstrProp, L""))
PutDispatchProperty(srpStyleTo, L"textDecoration", VT_BSTR, bstrProp);
}
varProp.Clear();
if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"backgroundcolor", VT_VARIANT, (void **)&varProp)))
PutDispatchProperty(srpStyleTo, L"backgroundcolor", VT_VARIANT, varProp);
varProp.Clear();
if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"color", VT_VARIANT, (void **)&varProp)))
PutDispatchProperty(srpStyleTo, L"color", VT_VARIANT, varProp);
varProp.Clear();
if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"fontSize", VT_VARIANT, (void **)&varProp)))
PutDispatchProperty(srpStyleTo, L"fontSize", VT_VARIANT, varProp);
varProp.Clear();
if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"height", VT_VARIANT, (void **)&varProp)))
PutDispatchProperty(srpStyleTo, L"height", VT_VARIANT, varProp);
varProp.Clear();
if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"letterSpacing", VT_VARIANT, (void **)&varProp)))
PutDispatchProperty(srpStyleTo, L"letterSpacing", VT_VARIANT, varProp);
varProp.Clear();
if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"lineHeight", VT_VARIANT, (void **)&varProp)))
PutDispatchProperty(srpStyleTo, L"lineHeight", VT_VARIANT, varProp);
varProp.Clear();
if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"paddingRight", VT_VARIANT, (void **)&varProp)))
PutDispatchProperty(srpStyleTo, L"paddingRight", VT_VARIANT, varProp);
varProp.Clear();
if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"paddingBottom", VT_VARIANT, (void **)&varProp)))
PutDispatchProperty(srpStyleTo, L"paddingBottom", VT_VARIANT, varProp);
varProp.Clear();
if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"paddingLeft", VT_VARIANT, (void **)&varProp)))
PutDispatchProperty(srpStyleTo, L"paddingLeft", VT_VARIANT, varProp);
varProp.Clear();
if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"paddingTop", VT_VARIANT, (void **)&varProp)))
PutDispatchProperty(srpStyleTo, L"paddingTop", VT_VARIANT, varProp);
}
}
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::DeleteTableRows
//
// Delete the table row(s) contained within the Trident selection. The
// entire operation is a single undo unit. Return S_OK or a Trident error.
//
HRESULT CTriEditDocument::DeleteTableRows(void)
{
HRESULT hr = S_OK;
CComPtr<IHTMLElement> srpTable;
struct SELCELLINFO selinfo[2]; // 0 is start cell, 1 is end cell
INT i=0;
CUndoPackManager undoPackMgr(m_pUnkTrident);
if (FAILED(hr = IsSelectionInTable((IDispatch**)&srpTable)))
goto Fail;
if (FAILED(hr = FillInSelectionCellsInfo(&selinfo[0], &selinfo[1])))
goto Fail;
undoPackMgr.Start();
for(i= selinfo[0].cRowIndex; i <= selinfo[1].cRowIndex; i++)
{
if (FAILED(hr = DeleteRowEx(srpTable, selinfo[0].cRowIndex)))
goto Fail;
}
Fail:
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::DeleteRowEx
//
// Delete the indicated table row. If the row is the only row in the table,
// delete the whole table. Return S_OK or a Trident error.
//
inline HRESULT CTriEditDocument::DeleteRowEx(IHTMLElement *pTable, LONG index)
{
HRESULT hr = S_OK;
CComPtr<IDispatch> srpRows;
INT cRows = 0;
if (FAILED(hr = GetDispatchProperty(pTable, L"rows", VT_DISPATCH, (void**)&srpRows)))
goto Fail;
if (FAILED(hr = GetDispatchProperty(srpRows, L"length", VT_I4, &cRows)))
goto Fail;
// if this is the only row in the table, delete the whole table
if (cRows == 1)
{
_ASSERT(index == 0);
hr = DeleteTable(pTable);
}
else
{
if (FAILED(hr = CallDispatchMethod(pTable, L"deleteRow", VTS_I4, index)))
goto Fail;
}
Fail:
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::DeleteCellEx
//
// Delete the indicated cell from the indicated row of the given table. If
// the cell is the only row in the table, delete the whole table. Return
// S_OK or a Trident error.
//
inline HRESULT CTriEditDocument::DeleteCellEx(IHTMLElement *pTable, IDispatch *pRow, LONG indexRow, LONG indexCell)
{
HRESULT hr = S_OK;
CComPtr<IDispatch> srpCells;
INT cCells = 0;
if (FAILED(hr = GetDispatchProperty(pRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
goto Fail;
if (FAILED(hr = GetDispatchProperty(srpCells, L"length", VT_I4, &cCells)))
goto Fail;
// if this is the only cell in the table, delete the whole row
if (cCells == 1)
{
_ASSERT(indexCell == 0);
hr = DeleteRowEx(pTable, indexRow);
}
else
{
if (FAILED(hr = CallDispatchMethod(pRow, L"deleteCell", VTS_I4, indexCell)))
goto Fail;
}
Fail:
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::DeleteTable
//
// Delete the given table. Return S_OK if all goes well; E_FAIL if something
// goes wrong.
//
HRESULT CTriEditDocument::DeleteTable(IHTMLElement *pTable)
{
CComPtr<IHTMLElement> srpParent;
HRESULT hr = E_FAIL;
_ASSERTE(pTable != NULL);
if (pTable == NULL)
goto Fail;
if (FAILED(hr=pTable->get_offsetParent(&srpParent)))
goto Fail;
_ASSERTE(srpParent != NULL);
if (FAILED(hr = SelectElement(pTable, srpParent)))
goto Fail;
hr = Exec(&CMDSETID_Forms3, IDM_DELETE, OLECMDEXECOPT_DONTPROMPTUSER, NULL, NULL);
Fail:
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::InsertTableRow
//
// Insert a new table row in to the table which contains the Trident selection,
// in the row preceding the selection. The new row will have the same number of
// cells as the row containing the selection. The colSpan of each new cell
// will be copied from the row containing the selection. The entire operation
// is a single undo unit. Returns S_OK or a Trident error.
//
HRESULT CTriEditDocument::InsertTableRow(void)
{
HRESULT hr = S_OK;
CComPtr<IDispatch> srpCell,srpCellNew, srpTable,srpCells,srpRows,srpNewRow,srpCellsNew;
LONG ccolSpan=0;
LONG cCells=0,i=0;
struct SELCELLINFO selinfo;
CUndoPackManager undoPackMgr(m_pUnkTrident);
undoPackMgr.Start();
if (FAILED(hr = IsSelectionInTable(&srpTable)))
goto Fail;
if (FAILED(hr = FillInSelectionCellsInfo(&selinfo, NULL)))
goto Fail;
if (FAILED(hr = CallDispatchMethod(srpTable, L"insertRow", VTS_I4, selinfo.cRowIndex)))
goto Fail;
if (FAILED(hr = GetDispatchProperty(srpTable, L"rows", VT_DISPATCH, (void**)&srpRows)))
goto Fail;
if (FAILED(hr = CallDispatchMethod(srpRows, L"Item", VTS_I4 VTS_DISPATCH_RETURN, selinfo.cRowIndex, &srpNewRow)))
goto Fail;
CopyStyle(selinfo.srpRow, srpNewRow);
// get the number of cells contains in the selected row
if (FAILED(hr = GetDispatchProperty(selinfo.srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
goto Fail;
if (FAILED(hr = GetDispatchProperty(srpCells, L"length", VT_I4, &cCells)))
goto Fail;
// now insert cells
for (i=cCells-1; i >=0; i--)
{
if (FAILED(hr = CallDispatchMethod(srpNewRow, L"insertCell", VTS_I4, 0)))
goto Fail;
srpCell.Release();
if (FAILED(hr = CallDispatchMethod(srpCells, L"Item", VTS_I4 VTS_DISPATCH_RETURN, i, &srpCell)))
goto Fail;
srpCellsNew.Release();
if (FAILED(hr = GetDispatchProperty(srpNewRow, L"cells", VT_DISPATCH, (void**)&srpCellsNew)))
goto Fail;
srpCellNew.Release();
if (FAILED(hr = CallDispatchMethod(srpCellsNew, L"Item", VTS_I4 VTS_DISPATCH_RETURN, 0, &srpCellNew)))
goto Fail;
CopyStyle(srpCell, srpCellNew);
CopyProperty(srpCell, srpCellNew);
{
VARIANT width;
VariantInit(&width);
if (SUCCEEDED(hr = GetDispatchProperty(srpCell, L"width", VT_VARIANT, &width)))
PutDispatchProperty(srpCellNew, L"width", VT_VARIANT, width);
}
if (SUCCEEDED(hr = GetDispatchProperty(srpCell, L"colSpan", VT_I4, &ccolSpan)))
PutDispatchProperty(srpCellNew, L"colSpan", VT_I4, ccolSpan);
}
Fail:
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::MapCellToFirstRowCell
//
// Given a table cell in pselInfo, return (by modifying pselInfo) the cell in
// the first row with the same column position, accounting for colSpans. Return
// S_OK or a Trident error.
//
HRESULT CTriEditDocument::MapCellToFirstRowCell(IDispatch *srpTable, struct SELCELLINFO *pselinfo)
{
HRESULT hr = 0;
CComPtr<IDispatch> srpCell, srpCells,srpRow,srpRows;
INT i=0,iCellIndex=0,iColSpanCurRow=0,cSpan=0,iColSpanFirstRow=0,crowSpan=0;
_ASSERTE(pselinfo != NULL);
// if current selection is not first row, find the corresponding first row cell index
if (pselinfo->cRowIndex == 0)
return S_OK;
srpCells.Release();
_ASSERTE(pselinfo->srpRow != NULL);
if (FAILED(hr = GetDispatchProperty(pselinfo->srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
goto Fail;
for (i=0; i < pselinfo->cCellIndex ; i++)
{
srpCell.Release();
_ASSERTE(srpCells != NULL);
if (FAILED(hr = CallDispatchMethod(srpCells, L"Item", VTS_I4 VTS_DISPATCH_RETURN, i, &srpCell)))
goto Fail;
_ASSERTE(srpCell != NULL);
if (FAILED(hr = GetDispatchProperty(srpCell, L"colSpan", VT_I4, &cSpan)))
goto Fail;
iColSpanCurRow += cSpan;
}
srpRows.Release();
_ASSERTE(srpTable != NULL);
if (FAILED(hr = GetDispatchProperty(srpTable, L"rows", VT_DISPATCH, (void**)&srpRows)))
goto Fail;
_ASSERTE(srpRows != NULL);
srpRow.Release();
if (FAILED(hr = CallDispatchMethod(srpRows, L"Item",VTS_I4 VTS_DISPATCH_RETURN, 0, &srpRow)))
goto Fail;
srpCells.Release();
if (FAILED(hr = GetDispatchProperty(srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
goto Fail;
iCellIndex=-1;
while(iColSpanCurRow >= iColSpanFirstRow)
{
iCellIndex++;
srpCell.Release();
_ASSERTE(srpCells != NULL);
if (FAILED(hr = CallDispatchMethod(srpCells, L"Item", VTS_I4 VTS_DISPATCH_RETURN, iCellIndex, &srpCell)))
goto Fail;
// we might hit the end. If so, first row is shorter than curret row and there's no mapping first row, bail out...
if (srpCell == NULL)
{
hr = E_FAIL;
goto Fail;
}
_ASSERTE(srpCell != NULL);
if (FAILED(hr = GetDispatchProperty(srpCell, L"colSpan", VT_I4, &cSpan)))
goto Fail;
iColSpanFirstRow += cSpan;
if (FAILED(hr = GetDispatchProperty(srpCell, L"rowSpan", VT_I4, &crowSpan)))
goto Fail;
if (crowSpan > pselinfo->cRowIndex)
{
iColSpanCurRow += cSpan;
}
}
pselinfo->srpCell = srpCell;
pselinfo->srpRow.Release();
if (FAILED(hr = GetTableRowElementAndTableFromCell(pselinfo->srpCell, NULL, &pselinfo->srpRow)))
goto Fail;
pselinfo->cRowIndex = 0;
_ASSERTE(iCellIndex >= 0);
pselinfo->cCellIndex = iCellIndex;
Fail:
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::InsertTableCol
//
// Insert a new column in to the table containing the selection, at the column
// of the selection. The entire operation is a single undo unit. Return S_OK
// or a Trident error.
//
HRESULT CTriEditDocument::InsertTableCol(void)
{
HRESULT hr = S_OK;
CComPtr<IDispatch> srpCellNew, srpTable,srpRows,srpRow,srpCells,srpCell;
LONG cRows=0,i=0, j=0, iColSpanInsert=0, iColSpanCur=0, cSpan=0,crowSpan = 0, cCells=0;
struct SELCELLINFO selinfo;
INT *pccolFix = NULL;
CUndoPackManager undoPackMgr(m_pUnkTrident);
undoPackMgr.Start();
if (FAILED(hr = IsSelectionInTable(&srpTable)))
goto Fail;
if (FAILED(hr = FillInSelectionCellsInfo(&selinfo, NULL)))
goto Fail;
MapCellToFirstRowCell(srpTable, &selinfo);
srpCells.Release();
_ASSERTE(selinfo.srpRow != NULL);
if (FAILED(hr = GetDispatchProperty(selinfo.srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
goto Fail;
_ASSERTE(srpTable != NULL);
if (FAILED(hr = GetDispatchProperty(srpTable, L"rows", VT_DISPATCH, (void**)&srpRows)))
goto Fail;
_ASSERTE(srpRows != NULL);
if (FAILED(hr = GetDispatchProperty(srpRows, L"length", VT_I4, &cRows)))
goto Fail;
pccolFix = new INT[cRows];
_ASSERTE(pccolFix != NULL);
for (i=0; i< cRows; i++)
*(pccolFix+i) = 0;
for (i=0; i < selinfo.cCellIndex; i++)
{
srpCell.Release();
_ASSERTE(srpCells != NULL);
if (FAILED(hr = CallDispatchMethod(srpCells, L"Item", VTS_I4 VTS_DISPATCH_RETURN, i, &srpCell))) goto Fail;
_ASSERTE(srpCell != NULL);
if (FAILED(hr = GetDispatchProperty(srpCell, L"colSpan", VT_I4, &cSpan)))
goto Fail;
iColSpanInsert += cSpan;
if (FAILED(hr = GetDispatchProperty(srpCell, L"rowSpan", VT_I4, &crowSpan)))
goto Fail;
// if someone before the current cell has row span, this needs to propogate to
// the next spanned rows
if (crowSpan > 1)
{
for (j= selinfo.cRowIndex+1; j < (selinfo.cRowIndex+crowSpan); j++)
*(pccolFix+j) += cSpan;
}
}
for (i=0; i < cRows;)
{
srpRow.Release();
_ASSERTE(srpRows != NULL);
if (FAILED(hr = CallDispatchMethod(srpRows, L"Item", VTS_I4 VTS_DISPATCH_RETURN, i, &srpRow)))
goto Fail;
srpCells.Release();
_ASSERTE(srpRow != NULL);
if (FAILED(hr = GetDispatchProperty(srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
goto Fail;
_ASSERTE(srpCells != NULL);
if (FAILED(hr = GetDispatchProperty(srpCells, L"length", VT_I4, &cCells)))
goto Fail;
iColSpanCur = *(pccolFix+i);
for (j=0; j < cCells; j++)
{
srpCell.Release();
if (FAILED(hr = CallDispatchMethod(srpCells, L"Item", VTS_I4 VTS_DISPATCH_RETURN, j, &srpCell))) goto Fail;
_ASSERTE(srpCell != NULL);
if (FAILED(hr = GetDispatchProperty(srpCell, L"colSpan", VT_I4, &cSpan)))
goto Fail;
if (iColSpanCur >= iColSpanInsert)
break;
iColSpanCur += cSpan;
}
_ASSERTE(srpRow != NULL);
if (FAILED(hr = CallDispatchMethod(srpRow, L"insertCell", VTS_I4, j)))
goto Fail;
srpCells.Release();
if (FAILED(hr = GetDispatchProperty(srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
goto Fail;
srpCellNew.Release();
if (FAILED(hr = CallDispatchMethod(srpCells, L"Item", VTS_I4 VTS_DISPATCH_RETURN, j, &srpCellNew)))
goto Fail;
if (!(!srpCell))
{
CopyStyle(srpCell, srpCellNew);
CopyProperty(srpCell, srpCellNew);
{
VARIANT height;
VariantInit(&height);
if (SUCCEEDED(hr = GetDispatchProperty(srpCell, L"height", VT_VARIANT, &height)))
PutDispatchProperty(srpCellNew, L"height", VT_VARIANT, height);
}
if (SUCCEEDED(GetDispatchProperty(srpCell, L"rowSpan", VT_I4, &cSpan)))
PutDispatchProperty(srpCellNew, L"rowSpan", VT_I4, cSpan);
}
// cSpan might be 0 if we are inserting a cell into an empty row
i += max(1, cSpan);
}
Fail:
if (pccolFix != NULL)
delete [] pccolFix;
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::DeleteTableCols
//
// Delete the table columns that are contained within the Trident selection.
// The entire operation is a single undo unit. Return S_OK or a Trident error.
//
HRESULT CTriEditDocument::DeleteTableCols(void)
{
CComPtr<IDispatch> srpRows,srpRow,srpCells,srpCell;
CComPtr<IHTMLElement> srpTable;
struct SELCELLINFO selinfo[2]; // 0 is start cell, 1 is end cell
LONG cRows=0, i=0, j=0, k=0, cCells=0;
HRESULT hr=0;
LONG iColSpanStart=0, iColSpanEnd=0,cColSpan=0,iColSpanCur=0, crowSpan=0;
INT * pccolFixStart=NULL, *pccolFixEnd = NULL;
CUndoPackManager undoPackMgr(m_pUnkTrident);
undoPackMgr.Start();
if (FAILED(hr = IsSelectionInTable((IDispatch**)&srpTable)))
goto Fail;
if (FAILED(hr = FillInSelectionCellsInfo(&selinfo[0], &selinfo[1])))
goto Fail;
if (!FAILED(MapCellToFirstRowCell(srpTable, &selinfo[1])))
MapCellToFirstRowCell(srpTable, &selinfo[0]);
_ASSERTE(selinfo[0].srpRow != NULL);
if (FAILED(hr = GetDispatchProperty(selinfo[0].srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
goto Fail;
_ASSERTE(srpCells != NULL);
if (FAILED(hr = GetDispatchProperty(srpCells, L"length", VT_I4, &cCells)))
goto Fail;
_ASSERTE(selinfo[1].cRowIndex == selinfo[0].cRowIndex);
_ASSERTE(selinfo[1].cCellIndex >= selinfo[0].cCellIndex);
srpRows.Release();
if (FAILED(hr = GetDispatchProperty(srpTable, L"rows", VT_DISPATCH, (void**)&srpRows)))
goto Fail;
_ASSERTE(srpRows != NULL);
if (FAILED(hr = GetDispatchProperty(srpRows, L"length", VT_I4, &cRows)))
goto Fail;
pccolFixEnd = new INT[cRows];
pccolFixStart = new INT[cRows];
for (i=0; i< cRows; i++)
{
*(pccolFixStart+i) = 0;
*(pccolFixEnd+i) = 0;
}
for (i=0; i<= selinfo[1].cCellIndex; i++)
{
srpCell.Release();
if (FAILED(hr = CallDispatchMethod(srpCells, L"Item", VTS_I4 VTS_DISPATCH_RETURN, i, &srpCell))) goto Fail;
if (FAILED(hr = GetDispatchProperty(srpCell, L"colSpan", VT_I4, &cColSpan)))
goto Fail;
if (i < selinfo[0].cCellIndex)
iColSpanStart += cColSpan;
if (i <= selinfo[1].cCellIndex)
iColSpanEnd += cColSpan;
if (FAILED(hr = GetDispatchProperty(srpCell, L"rowSpan", VT_I4, &crowSpan)))
goto Fail;
if (crowSpan > 1)
{
if (i < selinfo[0].cCellIndex)
{
for (j= selinfo[0].cRowIndex+1; j < selinfo[0].cRowIndex+crowSpan; j++)
*(pccolFixStart+j) += cColSpan;
}
if (i <= selinfo[1].cCellIndex)
{
for (j= selinfo[0].cRowIndex+1; j < selinfo[0].cRowIndex+crowSpan; j++)
*(pccolFixEnd+j) += cColSpan;
}
}
}
for (j=cRows-1; j >= 0; j--)
{
srpRow.Release();
if (FAILED(hr = CallDispatchMethod(srpRows, L"Item", VTS_I4 VTS_DISPATCH_RETURN, j, &srpRow)))
goto Fail;
srpCells.Release();
if (FAILED(hr = GetDispatchProperty(srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
goto Fail;
if (FAILED(hr = GetDispatchProperty(srpCells, L"length", VT_I4, &cCells)))
goto Fail;
iColSpanCur = 0;
_ASSERTE(iColSpanEnd-*(pccolFixEnd+j) >= 0);
_ASSERTE(iColSpanStart-*(pccolFixStart+j) >= 0);
for (i=0, k=0; iColSpanCur <= (iColSpanEnd-*(pccolFixEnd+j)) && k < cCells ; i++, k++)
{
srpCell.Release();
if (FAILED(hr = CallDispatchMethod(srpCells, L"Item", VTS_I4 VTS_DISPATCH_RETURN, i, &srpCell)))
goto Fail;
if (FAILED(hr = GetDispatchProperty(srpCell, L"colSpan", VT_I4, &cColSpan)))
goto Fail;
if (iColSpanCur >= (iColSpanStart-*(pccolFixStart+j)) && iColSpanCur < (iColSpanEnd-*(pccolFixEnd+j)))
{
if (FAILED(hr = DeleteCellEx(srpTable, srpRow, j, i)))
goto Fail;
i--; // we've deleted one cell, need to decrement cell index
}
iColSpanCur += cColSpan;
}
}
Fail:
if (pccolFixStart != NULL)
{
delete [] pccolFixStart;
}
if (pccolFixEnd != NULL)
{
delete [] pccolFixEnd;
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::InsertTableCell
//
// Insert a table cell before the cell containing the Trident selection; copy
// the properties and style of the cell containing the selection to the new
// cell. The entire operation is a single undo unit. Returns S_OK or a Trident
// error.
//
HRESULT CTriEditDocument::InsertTableCell(void)
{
HRESULT hr = S_OK;
struct SELCELLINFO selinfo;
CComPtr<IDispatch> srpCellNew, srpCells;
CUndoPackManager undoPackMgr(m_pUnkTrident);
undoPackMgr.Start();
if (FAILED(hr = FillInSelectionCellsInfo(&selinfo, NULL)))
goto Fail;
if (FAILED(hr = CallDispatchMethod(selinfo.srpRow, L"insertCell", VTS_I4, selinfo.cCellIndex)))
goto Fail;
srpCells.Release();
if (FAILED(hr = GetDispatchProperty(selinfo.srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
goto Fail;
srpCellNew.Release();
if (FAILED(hr = CallDispatchMethod(srpCells, L"Item", VTS_I4 VTS_DISPATCH_RETURN, selinfo.cCellIndex, &srpCellNew)))
goto Fail;
CopyStyle(selinfo.srpCell, srpCellNew);
CopyProperty(selinfo.srpCell, srpCellNew);
Fail:
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::DeleteTableCells
//
// Delete the table cells contained within the Trident selection. Delete entire
// rows as indicated. The entire operation is a single undo unit. Return
// S_OK or a Trident error.
//
HRESULT CTriEditDocument::DeleteTableCells(void)
{
CComPtr<IHTMLElement> srpTable,srpCells;
struct SELCELLINFO selinfo[2]; // 0 is start cell, 1 is end cell
LONG i=0, cCells=0;
HRESULT hr=0;
CUndoPackManager undoPackMgr(m_pUnkTrident);
undoPackMgr.Start();
if (FAILED(hr = IsSelectionInTable((IDispatch**)&srpTable)))
goto Fail;
if (FAILED(hr = FillInSelectionCellsInfo(&selinfo[0], &selinfo[1])))
goto Fail;
if (selinfo[0].cRowIndex == selinfo[1].cRowIndex) // same row
{
srpCells.Release();
if (FAILED(hr = GetDispatchProperty(selinfo[0].srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
goto Fail;
if (FAILED(hr = GetDispatchProperty(srpCells, L"length", VT_I4, &cCells)))
goto Fail;
// if the selection is select all the cells in this row, delete the whole row instead
if ( cCells == selinfo[1].cCellIndex+1 && selinfo[0].cCellIndex == 0)
{
if (FAILED(hr = DeleteRowEx(srpTable, selinfo[0].cRowIndex)))
goto Fail;
}
else // delete cell by cell
{
for (i = selinfo[1].cCellIndex; i >= selinfo[0].cCellIndex; i--)
{
if (FAILED(hr = DeleteCellEx(srpTable, selinfo[0].srpRow, selinfo[0].cRowIndex, i)))
goto Fail;
}
}
}
else
{
srpCells.Release();
if (FAILED(hr = GetDispatchProperty(selinfo[1].srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
goto Fail;
if (FAILED(hr = GetDispatchProperty(srpCells, L"length", VT_I4, &cCells)))
goto Fail;
// if the selection ends at the last cell of the row, delete the whole row instead
if ( cCells == selinfo[1].cCellIndex+1)
{
if (FAILED(hr = DeleteRowEx(srpTable, selinfo[1].cRowIndex)))
goto Fail;
}
else // delete cell by cell
{
for (i = selinfo[1].cCellIndex; i >= 0; i--)
{
if (FAILED(hr = DeleteCellEx(srpTable, selinfo[1].srpRow, selinfo[1].cRowIndex, i)))
goto Fail;
}
}
for (i = selinfo[1].cRowIndex-1; i > selinfo[0].cRowIndex; i--)
{
if (FAILED(hr = DeleteRowEx(srpTable, i)))
goto Fail;
}
if (selinfo[0].cCellIndex == 0) // if the selection is from first cell of a row across other rows, delete the whole row instead
{
if (FAILED(hr = DeleteRowEx(srpTable, selinfo[0].cRowIndex)))
goto Fail;
}
else // delete cell by cell
{
srpCells.Release();
if (FAILED(hr = GetDispatchProperty(selinfo[0].srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
goto Fail;
if (FAILED(hr = GetDispatchProperty(srpCells, L"length", VT_I4, &cCells)))
goto Fail;
for (i = cCells-1; i >= selinfo[0].cCellIndex; i--)
{
if (FAILED(hr = DeleteCellEx(srpTable, selinfo[0].srpRow, selinfo[0].cRowIndex, i)))
goto Fail;
}
}
}
Fail:
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::MergeTableCells
//
// Merge the indicated cells in to a single cell, and adjust its colSpan.
// The cells must be within a single table row. The innerHTML of all merged cells
// is concatenated and placed in the remaining cell. Return S_OK or a Trident error.
//
HRESULT CTriEditDocument::MergeTableCells(IDispatch* srpTable, INT iRow, INT iIndexStart, INT iIndexEnd)
{
CComPtr<IDispatch> srpCells,srpRows,srpCurRow,srpCell;
INT ccolSpanTotal=0, i=0, ccolSpan=0;
HRESULT hr=0;
CComBSTR bstrText;
CComBSTR bstrMergedText;
if (FAILED(hr = GetDispatchProperty(srpTable, L"rows", VT_DISPATCH, (void**)&srpRows)))
goto Fail;
if (FAILED(hr = CallDispatchMethod(srpRows, L"Item", VTS_I4 VTS_DISPATCH_RETURN, iRow, &srpCurRow)))
goto Fail;
srpCells.Release();
if (FAILED(hr = GetDispatchProperty(srpCurRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
goto Fail;
bstrMergedText.Empty();
ccolSpanTotal = 0;
for (i = iIndexEnd; i >= iIndexStart; i--)
{
srpCell.Release();
if (FAILED(hr = CallDispatchMethod(srpCells, L"Item", VTS_I4 VTS_DISPATCH_RETURN, i, &srpCell)))
goto Fail;
bstrText.Empty();
if (FAILED(hr = GetDispatchProperty(srpCell, L"innerHTML", VT_BSTR, &bstrText)))
goto Fail;
bstrText += bstrMergedText;
bstrMergedText = bstrText;
if (FAILED(hr = GetDispatchProperty(srpCell, L"colSpan", VT_I4, &ccolSpan)))
goto Fail;
ccolSpanTotal += ccolSpan;
if (i != iIndexStart)
{
if (FAILED(hr = DeleteCellEx((IHTMLElement*)srpTable, srpCurRow, iRow, i)))
goto Fail;
}
else
{
if (FAILED(hr = PutDispatchProperty(srpCell, L"colSpan", VT_I4, ccolSpanTotal)))
goto Fail;
if (FAILED(hr = PutDispatchProperty(srpCell, L"innerHTML", VT_BSTR, bstrMergedText)))
goto Fail;
}
}
Fail:
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::MergeTableCells
//
// Merge the cells in the Trident selection in to a single cell, and adjust that
// cell's colSpan. The cells must be within a single table row. The innerHTML of
// all merged cells is concatenated and placed in the remaining cell. Return S_OK
// or a Trident error.
//
HRESULT CTriEditDocument::MergeTableCells(void)
{
CComPtr<IDispatch> srpCell, srpCells,srpElement,srpRows,srpRow;
CComPtr<IHTMLElement> srpTable;
struct SELCELLINFO selinfo[2]; // 0 is start cell, 1 is end cell
LONG i=0, cCells=0;
HRESULT hr=0;
CComBSTR bstrText;
CComBSTR bstrMergedText;
CUndoPackManager undoPackMgr(m_pUnkTrident);
undoPackMgr.Start();
if (FAILED(hr = IsSelectionInTable((IDispatch**)&srpTable)))
goto Fail;
if (FAILED(hr = FillInSelectionCellsInfo(&selinfo[0], &selinfo[1])))
goto Fail;
if (selinfo[0].cRowIndex == selinfo[1].cRowIndex)
{
if (selinfo[1].cCellIndex == selinfo[0].cCellIndex)
{
hr = S_OK;
goto Fail;
}
if (FAILED(hr = MergeTableCells(srpTable, selinfo[0].cRowIndex, selinfo[0].cCellIndex, selinfo[1].cCellIndex)))
goto Fail;
}
else
{
srpCells.Release();
if (FAILED(hr = GetDispatchProperty(selinfo[1].srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
goto Fail;
if (FAILED(hr = MergeTableCells(srpTable, selinfo[1].cRowIndex, 0, selinfo[1].cCellIndex)))
goto Fail;
if (FAILED(hr = GetDispatchProperty(srpTable, L"rows", VT_DISPATCH, (void**)&srpRows)))
goto Fail;
for (i = selinfo[1].cRowIndex-1; i > selinfo[0].cRowIndex; i--)
{
srpElement.Release();
if (FAILED(hr = CallDispatchMethod(srpRows, L"Item", VTS_I4 VTS_DISPATCH_RETURN, i, &srpElement)))
goto Fail;
srpCells.Release();
if (FAILED(hr = GetDispatchProperty(srpElement, L"cells", VT_DISPATCH, (void**)&srpCells)))
goto Fail;
if (FAILED(hr = GetDispatchProperty(srpCells, L"length", VT_I4, &cCells)))
goto Fail;
if (FAILED(hr = MergeTableCells(srpTable, i, 0, cCells-1)))
goto Fail;
}
srpCells.Release();
if (FAILED(hr = GetDispatchProperty(selinfo[0].srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
goto Fail;
if (FAILED(hr = GetDispatchProperty(srpCells, L"length", VT_I4, &cCells)))
goto Fail;
if (FAILED(hr = MergeTableCells(srpTable, selinfo[0].cRowIndex, selinfo[0].cCellIndex, cCells-1)))
goto Fail;
bstrMergedText.Empty();
for (i = selinfo[0].cRowIndex; i <= selinfo[1].cRowIndex; i++)
{
srpRows.Release();
if (FAILED(hr = GetDispatchProperty(srpTable, L"rows", VT_DISPATCH, (void**)&srpRows)))
goto Fail;
srpRow.Release();
if (FAILED(hr = CallDispatchMethod(srpRows, L"Item", VTS_I4 VTS_DISPATCH_RETURN, selinfo[0].cRowIndex, &srpRow)))
goto Fail;
srpCells.Release();
if (FAILED(hr = GetDispatchProperty(srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
goto Fail;
srpCell.Release();
if (FAILED(hr = CallDispatchMethod(srpCells, L"Item", VTS_I4 VTS_DISPATCH_RETURN, 0, &srpCell)))
goto Fail;
bstrText.Empty();
if (FAILED(hr = GetDispatchProperty(srpCell, L"innerHTML", VT_BSTR, &bstrText)))
goto Fail;
bstrMergedText += L"<P>";
bstrMergedText += bstrText;
bstrMergedText += L"</P>";
if (i != selinfo[1].cRowIndex)
{
if (FAILED(hr = DeleteRowEx(srpTable, selinfo[0].cRowIndex)))
goto Fail;
}
}
if (FAILED(hr = PutDispatchProperty(srpCell, L"innerHTML", VT_BSTR, bstrMergedText)))
goto Fail;
}
Fail:
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::SplitTableCell
//
// Split the indicated table cell in to two cells and adjust the colSpan
// of the relevant cells in the other rows as needed. The entire operation is
// a single undo unit. Return S_OK or a Trident error.
//
HRESULT CTriEditDocument::SplitTableCell(IDispatch *srpTable, INT iRow, INT index)
{
CComPtr<IDispatch> srpCellSplit, srpCells,srpCell,srpElement,srpRows,srpRow,srpCurRow,srpCellNew;
INT cRows=0,i=0,j=0,ccolSpan=0,ccolSpanCur=0,crowSpan=0, cCells=0;
HRESULT hr=0;
CComBSTR bstrText;
INT *pccolFix = NULL;
CUndoPackManager undoPackMgr(m_pUnkTrident);
undoPackMgr.Start();
if (FAILED(hr = GetDispatchProperty(srpTable, L"rows", VT_DISPATCH, (void**)&srpRows)))
goto Fail;
if (FAILED(hr = GetDispatchProperty(srpRows, L"length", VT_I4, &cRows)))
goto Fail;
if (FAILED(hr = CallDispatchMethod(srpRows, L"Item", VTS_I4 VTS_DISPATCH_RETURN, iRow, &srpCurRow)))
goto Fail;
if (FAILED(hr = CallDispatchMethod(srpCurRow, L"insertCell", VTS_I4, index+1)))
goto Fail;
srpCells.Release();
if (FAILED(hr = GetDispatchProperty(srpCurRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
goto Fail;
srpCellNew.Release();
if (FAILED(hr = CallDispatchMethod(srpCells, L"Item", VTS_I4 VTS_DISPATCH_RETURN, index+1, &srpCellNew)))
goto Fail;
srpCellSplit.Release();
if (FAILED(hr = CallDispatchMethod(srpCells, L"Item", VTS_I4 VTS_DISPATCH_RETURN, index, (void**)&srpCellSplit)))
goto Fail;
ccolSpan=0;
if (FAILED(hr = GetDispatchProperty(srpCellSplit, L"colSpan", VT_I4, &ccolSpan)))
goto Fail;
CopyStyle(srpCellSplit, srpCellNew);
CopyProperty(srpCellSplit, srpCellNew);
if (ccolSpan == 1)
{
INT ccolSpanStart = 0,ccolSpanEnd=0;
INT ccolSpanTmp = 0, cRowSpan = 0;
pccolFix = new INT[cRows];
for (j=0; j < cRows; j++)
*(pccolFix+j) = 0;
for (j=0; j<index;j++)
{
srpCell.Release();
if (FAILED(hr = CallDispatchMethod(srpCells, L"Item", VTS_I4 VTS_DISPATCH_RETURN, j, (void**)&srpCell)))
goto Fail;
ccolSpanTmp = 0;
if (FAILED(hr = GetDispatchProperty(srpCell, L"colSpan", VT_I4, &ccolSpanTmp)))
goto Fail;
ccolSpanStart += ccolSpanTmp;
if (FAILED(hr = GetDispatchProperty(srpCell, L"rowSpan", VT_I4, &cRowSpan)))
goto Fail;
if (cRowSpan > 1)
for (i = index+1; i < index+cRowSpan; i++)
*(pccolFix+i) += ccolSpanTmp;
}
ccolSpanEnd = ccolSpanStart + ccolSpan;
for (j=0; j < cRows; j++)
{
if (j == iRow)
continue;
srpRow.Release();
if (FAILED(hr = CallDispatchMethod(srpRows, L"Item", VTS_I4 VTS_DISPATCH_RETURN, j, &srpRow)))
goto Fail;
srpCells.Release();
if (FAILED(hr = GetDispatchProperty(srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
goto Fail;
if (FAILED(hr = GetDispatchProperty(srpCells, L"length", VT_I4, &cCells)))
goto Fail;
ccolSpanCur = *(pccolFix+j);
for(i=0 ; i < cCells; i++)
{
srpCell.Release();
if (FAILED(hr = CallDispatchMethod(srpCells, L"Item", VTS_I4 VTS_DISPATCH_RETURN, i, &srpCell)))
goto Fail;
ccolSpan=0;
if (FAILED(hr = GetDispatchProperty(srpCell, L"colSpan", VT_I4, &ccolSpan)))
goto Fail;
if (ccolSpanStart <= ccolSpanCur && ccolSpanCur < ccolSpanEnd)
{
if (FAILED(hr = PutDispatchProperty(srpCell, L"colSpan", VT_I4, ccolSpan+1)))
goto Fail;
}
if (ccolSpanCur >= ccolSpanEnd)
break;
ccolSpanCur += ccolSpan;
}
}
}
else
{
if (FAILED(hr = PutDispatchProperty(srpCellNew, L"colSpan", VT_I4, ccolSpan/2)))
goto Fail;
if (FAILED(hr = PutDispatchProperty(srpCellSplit, L"colSpan", VT_I4, ccolSpan-ccolSpan/2)))
goto Fail;
}
// now copy row span
if (FAILED(hr = GetDispatchProperty(srpCellSplit, L"rowSpan", VT_I4, &crowSpan)))
goto Fail;
if (FAILED(hr = PutDispatchProperty(srpCellNew, L"rowSpan", VT_I4, crowSpan)))
goto Fail;
Fail:
if (pccolFix != NULL)
{
delete [] pccolFix;
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::SplitTableCell
//
// Split the table cell in the Trident selection in to two cells and adjust the
// colSpan of the relevant cells in the other rows as needed. The entire operation
// is a single undo unit. Return S_OK or a Trident error.
//
HRESULT CTriEditDocument::SplitTableCell(void)
{
CComPtr<IDispatch> srpCell, srpTable,srpCells,srpElement,srpRows,srpRow;
struct SELCELLINFO selinfo[2]; // 0 is start cell, 1 is end cell
LONG i=0, j=0,cCells=0;
HRESULT hr=0;
CUndoPackManager undoPackMgr(m_pUnkTrident);
undoPackMgr.Start();
if (FAILED(hr = IsSelectionInTable(&srpTable)))
goto Fail;
if (FAILED(hr = FillInSelectionCellsInfo(&selinfo[0], &selinfo[1])))
goto Fail;
if (FAILED(hr = GetDispatchProperty(srpTable, L"rows", VT_DISPATCH, (void**)&srpRows)))
goto Fail;
if (selinfo[0].cRowIndex == selinfo[1].cRowIndex)
{
for (i = selinfo[1].cCellIndex; i >= selinfo[0].cCellIndex; i--)
{
if (FAILED(hr = SplitTableCell(srpTable, selinfo[0].cRowIndex, i)))
goto Fail;
}
}
else
{
for (i = selinfo[1].cCellIndex; i >= 0; i--)
{
if (FAILED(hr = SplitTableCell(srpTable, selinfo[1].cRowIndex, i)))
goto Fail;
}
for (i = selinfo[1].cRowIndex-1; i > selinfo[0].cRowIndex; i--)
{
srpElement.Release();
if (FAILED(hr = CallDispatchMethod(srpRows, L"Item", VTS_I4 VTS_DISPATCH_RETURN, i, &srpElement)))
goto Fail;
srpCells.Release();
if (FAILED(hr = GetDispatchProperty(srpElement, L"cells", VT_DISPATCH, (void**)&srpCells)))
goto Fail;
if (FAILED(hr = GetDispatchProperty(srpCells, L"length", VT_I4, &cCells)))
goto Fail;
for (j = cCells-1; j >= 0; j--)
{
if (FAILED(hr = SplitTableCell(srpTable, i, j)))
goto Fail;
}
}
srpCells.Release();
if (FAILED(hr = GetDispatchProperty(selinfo[0].srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
goto Fail;
if (FAILED(hr = GetDispatchProperty(srpCells, L"length", VT_I4, &cCells)))
goto Fail;
for (i = cCells-1; i >= selinfo[0].cCellIndex; i--)
{
if (FAILED(hr = SplitTableCell(srpTable, selinfo[0].cRowIndex, i)))
goto Fail;
}
}
Fail:
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::InsertTable
//
// Insert a table in to the document at the selection point. All parameters
// are optional and taken from members of pvarargIn as follows:
//
// pvarargIn[0] I4 - Number of rows; default 0.
// pvarargIn[1] I4 - Number of columns; default 0.
// pvarargIn[2] BSTR - Table tag attributes; default "".
// pvarargIn[3] BSTR - Table cell attributes; default "".
// pvarargIn[4] BSTR - Table caption; default "".
//
// pvarArgIn must be sipplied even if the default values are to be used for
// all parameters. The entire operation is a single undo unit. The wait cursor
// is displayed since this can be a fairly time-consuming operation. Returns S_OK
// or a Trident error.
//
HRESULT CTriEditDocument::InsertTable(VARIANTARG *pvarargIn)
{
HRESULT hr=0;
CComPtr<IHTMLSelectionObject> srpSel;
CComPtr<IDispatch> srpRange;
CComPtr<IDispatch> srpCell;
CComPtr<IHTMLDocument2> srpiHTMLDoc;
CComBSTR bstrHtml;
CComBSTR bstrTblAttr;
CComBSTR bstrTCellAttr;
CComBSTR bstrCaption;
int i=0, j=0, iRow=0, iCol=0;
VARIANT rgvar[5];
HCURSOR hOldCursor;
if (pvarargIn == NULL)
return E_FAIL;
hOldCursor = ::SetCursor(::LoadCursor(NULL, IDC_WAIT));
for(i = 0; i < sizeof(rgvar)/sizeof(VARIANT); i++)
VariantInit(&rgvar[i]);
// default
iRow=1;
iCol=1;
bstrTCellAttr.Empty();
bstrTblAttr.Empty();
if (pvarargIn != NULL)
{
LONG lLBound=0, lUBound=0,lIndex=0;
SAFEARRAY *psa;
LONG cParam; // number of parameters host passes in
psa = V_ARRAY(pvarargIn);
SafeArrayGetLBound(psa, 1, &lLBound);
SafeArrayGetUBound(psa, 1, &lUBound);
cParam = 0;
_ASSERTE(lLBound == 0);
_ASSERTE(lUBound - lLBound < 5);
for (lIndex = lLBound; lIndex <= lUBound && cParam < sizeof(rgvar)/sizeof(VARIANT); lIndex++)
{
SafeArrayGetElement(psa, &lIndex, &rgvar[cParam++]);
}
// first element: number of rows
if (cParam >= 1)
iRow = V_I4(&rgvar[0]);
// 2'rd element: number of columns
if (cParam >= 2)
iCol = V_I4(&rgvar[1]);
// 3'rd element: table tag attributes
if (cParam >= 3)
bstrTblAttr = V_BSTR(&rgvar[2]);
// 4'th element: table cell tag attributes
if (cParam >= 4)
bstrTCellAttr = V_BSTR(&rgvar[3]);
if (cParam >= 5)
bstrCaption = V_BSTR(&rgvar[4]);
}
if (iRow < 0 || iCol < 0)
goto Fail;
bstrHtml.Empty();
bstrHtml += "<TABLE ";
if (bstrTblAttr != NULL)
bstrHtml += bstrTblAttr;
bstrHtml += ">";
if (bstrCaption != NULL)
{
bstrHtml += "<CAPTION>";
bstrHtml += bstrCaption;
bstrHtml += "</CAPTION>";
}
bstrHtml +="<TBODY>";
for (i=0; i<iRow; i++)
{
bstrHtml += "<TR>";
for (j=0; j<iCol; j++)
{
bstrHtml += "<TD ";
if (bstrTCellAttr != NULL)
bstrHtml += bstrTCellAttr;
bstrHtml +="></TD>";
}
bstrHtml += "</TR>";
}
bstrHtml += "</TBODY></TABLE>";
if (FAILED(hr = m_pUnkTrident->QueryInterface(IID_IHTMLDocument2, (void**)&srpiHTMLDoc)))
goto Fail;
if (FAILED(hr = srpiHTMLDoc->get_selection(&srpSel)))
goto Fail;
if (FAILED(hr = CallDispatchMethod(srpSel, L"createRange", VTS_DISPATCH_RETURN, (void**)&srpRange)))
goto Fail;
if (FAILED(hr = CallDispatchMethod(srpRange, L"pasteHTML", VTS_BSTR, bstrHtml)))
goto Fail;
Fail:
for(i = 0; i < sizeof(rgvar)/sizeof(VARIANT); i++)
VariantClear(&rgvar[i]);
::SetCursor(hOldCursor);
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::DoVerb
//
// Execute the verb in pvarargIn (or OLEIVERB_PRIMARY if pvarargIn is NULL)
// on the current object (which must QI for IHTMLObjectElement). Return E_FAIL
// or the code returned as a result of executing the verb,
//
HRESULT CTriEditDocument::DoVerb(VARIANTARG *pvarargIn, BOOL fQueryStatus)
{
LONG iVerb;
IHTMLObjectElement *piHTMLObjectElement = NULL;
IDispatch *pDisp = NULL;
IOleObject *pOleObj = NULL;
HRESULT hr = E_FAIL;
_ASSERTE(m_pihtmlElement != NULL);
if (SUCCEEDED(m_pihtmlElement->QueryInterface(IID_IHTMLObjectElement, (void **)&piHTMLObjectElement)) && piHTMLObjectElement)
{
if (SUCCEEDED(piHTMLObjectElement->get_object(&pDisp)) && pDisp)
{
if (SUCCEEDED(pDisp->QueryInterface(IID_IOleObject, (void **)&pOleObj)) && pOleObj)
{
if (fQueryStatus) // In the query status case, we're done
hr = S_OK;
else
{
if (pvarargIn == NULL)
iVerb = OLEIVERB_PRIMARY;
else if (pvarargIn->vt == VT_I4)
iVerb = V_I4(pvarargIn);
else
{
hr = E_INVALIDARG;
goto LSkipDoVerb;
}
GetTridentWindow();
_ASSERTE(m_hwndTrident != NULL);
hr = pOleObj->DoVerb(iVerb, NULL, NULL, 0, m_hwndTrident, NULL);
}
LSkipDoVerb:
pOleObj->Release();
}
pDisp->Release();
}
piHTMLObjectElement->Release();
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::GetDocument
//
// Return the IHTMLDocument pointer (under *ppihtmlDocument) and S_OK, or
// E_FAIL/E_POINTER.
//
STDMETHODIMP CTriEditDocument::GetDocument(IHTMLDocument2** ppihtmlDocument)
{
_ASSERTE(ppihtmlDocument);
if (ppihtmlDocument)
{
if (m_pUnkTrident)
{
return m_pUnkTrident->QueryInterface(IID_IHTMLDocument2,
(LPVOID*)ppihtmlDocument);
}
return E_FAIL;
}
return E_POINTER;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::GetAllColllection
//
// Return the all collection of the HTML document (under *ppihtmlCollection),
// or E_FAIL.
//
STDMETHODIMP CTriEditDocument::GetAllCollection(IHTMLElementCollection** ppihtmlCollection)
{
IHTMLDocument2* pihtmlDoc2;
HRESULT hr=E_FAIL;
_ASSERTE(ppihtmlCollection);
if (ppihtmlCollection && SUCCEEDED(GetDocument(&pihtmlDoc2)))
{
_ASSERTE(pihtmlDoc2);
hr = pihtmlDoc2->get_all(ppihtmlCollection);
pihtmlDoc2->Release();
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::GetCollectionElement
//
// Return the indicated element from the given collection under *ppihtmlElement.
// Return S_OK if all goes well,or E_FAIL or a Triedent error on error.
//
STDMETHODIMP CTriEditDocument::GetCollectionElement(
IHTMLElementCollection* pihtmlCollection,
LONG iElem, IHTMLElement** ppihtmlElement)
{
VARIANT var;
VARIANT varEmpty;
IDispatch* pidispElement=NULL;
HRESULT hr = E_FAIL;
_ASSERTE(pihtmlCollection && iElem >= 0 && ppihtmlElement);
if (!pihtmlCollection || iElem < 0 || !ppihtmlElement)
return E_POINTER;
*ppihtmlElement = NULL; //initialize [out] parameter
VariantInit(&var);
var.vt = VT_I4;
var.lVal = iElem;
VariantInit(&varEmpty);
varEmpty.vt = VT_EMPTY;
hr = pihtmlCollection->item(var, varEmpty, &pidispElement);
if (SUCCEEDED(hr))
{
if (pidispElement)
{
hr = pidispElement->QueryInterface(IID_IHTMLElement, (LPVOID*)ppihtmlElement);
pidispElement->Release();
}
else
{
hr = E_FAIL;
}
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
//
// CTriEditDocument::Is2DCapable
//
// Return (under *pfBool) TRUE if the given HTML element can be positioned
// out of the flow as a 2D element, or FALSE if not. Return S_OK in either
// case. Return E_FAIL or a Trident error if something goes wrong.
//
STDMETHODIMP CTriEditDocument::Is2DCapable(IHTMLElement* pihtmlElement, BOOL* pfBool)
{
HRESULT hr= E_FAIL;
CComBSTR bstrTag;
_ASSERTE(pihtmlElement);
if (!pihtmlElement || !pfBool)
return E_POINTER;
*pfBool = FALSE;
bstrTag.Empty();
if (FAILED(hr = GetDispatchProperty(pihtmlElement, L"tagName", VT_BSTR, &bstrTag)))
return E_FAIL;
if (lstrcmpi(_T("APPLET"), OLE2T(bstrTag)) == 0 ||
lstrcmpi(_T("BUTTON"), OLE2T(bstrTag)) == 0 ||
lstrcmpi(_T("DIV"), OLE2T(bstrTag)) == 0 ||
lstrcmpi(_T("EMBED"), OLE2T(bstrTag)) == 0 ||
lstrcmpi(_T("FIELDSET"), OLE2T(bstrTag)) == 0 ||
lstrcmpi(_T("HR"), OLE2T(bstrTag)) == 0 ||
lstrcmpi(_T("IFRAME"), OLE2T(bstrTag)) == 0 ||
lstrcmpi(_T("IMG"), OLE2T(bstrTag)) == 0 ||
lstrcmpi(_T("INPUT"), OLE2T(bstrTag)) == 0 ||
lstrcmpi(_T("MARQUEE"), OLE2T(bstrTag)) == 0 ||
lstrcmpi(_T("OBJECT"), OLE2T(bstrTag)) == 0 ||
lstrcmpi(_T("SELECT"), OLE2T(bstrTag)) == 0 ||
lstrcmpi(_T("SPAN"), OLE2T(bstrTag)) == 0 ||
lstrcmpi(_T("TABLE"), OLE2T(bstrTag)) == 0 ||
lstrcmpi(_T("TEXTAREA"), OLE2T(bstrTag)) == 0 )
{
*pfBool = TRUE;
return S_OK;
}
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::SelectElement
//
// Select the given element within Trident as a site selection. Return S_OK or
// a Trident error.
//
STDMETHODIMP CTriEditDocument::SelectElement(IHTMLElement* pihtmlElement, IHTMLElement* pihtmlElementParent)
{
IHTMLControlElement* picont=NULL;
IHTMLElement* piParent=NULL;
IDispatch* pidisp=NULL;
IHTMLTextContainer* pitext=NULL;
IHTMLControlRange* pirange=NULL;
HRESULT hr;
CComBSTR bstrTag;
if ( !pihtmlElement || !pihtmlElementParent )
return E_FAIL;
hr = pihtmlElement->QueryInterface(IID_IHTMLControlElement, (LPVOID*)&picont);
if ( FAILED(hr) )
goto CleanUp;
_ASSERTE(picont);
hr = pihtmlElementParent->QueryInterface(IID_IHTMLTextContainer, (LPVOID*)&pitext);
if ( FAILED(hr) )
goto CleanUp;
_ASSERTE(pitext);
hr = pitext->createControlRange(&pidisp);
if ( FAILED(hr) )
goto CleanUp;
_ASSERTE(pitext);
hr = pidisp->QueryInterface(IID_IHTMLControlRange, (LPVOID*)&pirange);
if ( FAILED(hr) )
goto CleanUp;
_ASSERTE(pirange);
hr = pirange->add(picont);
if ( FAILED(hr) )
goto CleanUp;
hr = pirange->select();
CleanUp:
SAFERELEASE(picont);
SAFERELEASE(piParent);
SAFERELEASE(pidisp);
SAFERELEASE(pitext);
SAFERELEASE(pirange);
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::IsElementDTC
//
// Return S_OK if the given element is a DTC (Design-Time Control) or E_FAIL
// if not.
//
HRESULT CTriEditDocument::IsElementDTC(IHTMLElement *pihtmlElement)
{
IHTMLObjectElement *piHTMLObjectElement = NULL;
IDispatch *pDisp = NULL;
IActiveDesigner *piActiveDesigner = NULL;
IUnknown *piUnk = NULL;
if (SUCCEEDED(pihtmlElement->QueryInterface(IID_IHTMLObjectElement, (void **)&piHTMLObjectElement)) && piHTMLObjectElement)
{
if (SUCCEEDED(piHTMLObjectElement->get_object(&pDisp)) && pDisp)
{
if (SUCCEEDED(pDisp->QueryInterface(IID_IUnknown, (void **)&piUnk)) && piUnk)
{
if (SUCCEEDED(piUnk->QueryInterface(IID_IActiveDesigner, (void **)&piActiveDesigner)) && piActiveDesigner)
{
piHTMLObjectElement->Release();
pDisp->Release();
piUnk->Release();
piActiveDesigner->Release();
return S_OK;
}
piUnk->Release();
}
pDisp->Release();
}
piHTMLObjectElement->Release();
}
return E_FAIL;
}