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
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;
|
|
}
|