mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-31 22:25:30 +00:00
1596 lines
41 KiB
C++
1596 lines
41 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
|
|
|
|
//
|
|
//
|
|
// Editor save stuff. LWT 06/01/95
|
|
// this should be on the branch
|
|
//
|
|
|
|
#ifdef EDITOR
|
|
|
|
#include "editor.h"
|
|
#ifdef XP_UNIX
|
|
#include <unistd.h> /* for getpid() */
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
|
|
const char* kCommandNames[kCommandIDMax+1] = {
|
|
"Null",
|
|
"Typing",
|
|
"AddText",
|
|
"DeleteText",
|
|
"Cut",
|
|
"PasteText",
|
|
"PasteHTML",
|
|
"PasteHREF",
|
|
"ChangeAttributes",
|
|
"Indent",
|
|
"ParagraphAlign",
|
|
"MorphContainer",
|
|
"InsertHorizRule",
|
|
"SetHorizRuleData",
|
|
"InsertImage",
|
|
"SetImageData",
|
|
"InsertBreak",
|
|
"ChangePageData",
|
|
"SetMetaData",
|
|
"DeleteMetaData",
|
|
"InsertTarget",
|
|
"SetTargetData",
|
|
"InsertUnknownTag",
|
|
"SetUnknownTagData",
|
|
"GroupOfChanges",
|
|
"SetListData",
|
|
"InsertTable",
|
|
"DeleteTable",
|
|
"SetTableData",
|
|
"InsertTableCaption",
|
|
"SetTableCaptionData",
|
|
"DeleteTableCaption",
|
|
"InsertTableRow",
|
|
"SetTableRowData",
|
|
"DeleteTableRow",
|
|
"InsertTableColumn",
|
|
"SetTableCellData",
|
|
"DeleteTableColumn",
|
|
"InsertTableCell",
|
|
"DeleteTableCell",
|
|
"InsertMultiColumn",
|
|
"DeleteMultiColumn",
|
|
"SetMultiColumnData",
|
|
"SetSelection"
|
|
};
|
|
|
|
#endif
|
|
|
|
CEditText::CEditText() { m_pChars = NULL; m_iLength = 0; m_iCount = 0; }
|
|
CEditText::~CEditText() { Clear(); }
|
|
|
|
void CEditText::Clear() {
|
|
if ( m_pChars )
|
|
XP_HUGE_FREE(m_pChars); // Tied to implementation of CStreamOutMemory
|
|
m_pChars = 0;
|
|
m_iCount = 0;
|
|
m_iLength = 0;
|
|
}
|
|
|
|
char* CEditText::GetChars() { return m_pChars; }
|
|
int32 CEditText::Length() { return m_iLength; }
|
|
char** CEditText::GetPChars() { return &m_pChars; }
|
|
int32* CEditText::GetPLength() { return &m_iLength; }
|
|
|
|
// CEditCommand
|
|
|
|
CEditCommand::CEditCommand(CEditBuffer* editBuffer, intn id)
|
|
{
|
|
m_id = id;
|
|
m_editBuffer = editBuffer;
|
|
}
|
|
|
|
CEditCommand::~CEditCommand()
|
|
{
|
|
}
|
|
|
|
void CEditCommand::Do()
|
|
{
|
|
}
|
|
|
|
void CEditCommand::Undo()
|
|
{
|
|
}
|
|
|
|
void CEditCommand::Redo()
|
|
{
|
|
Do();
|
|
}
|
|
|
|
intn CEditCommand::GetID()
|
|
{
|
|
return m_id;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
void CEditCommand::Print(IStreamOut& stream) {
|
|
const char* name = "Unknown";
|
|
if ( m_id >= 0 && m_id <= kCommandIDMax ){
|
|
name = kCommandNames[m_id];
|
|
}
|
|
stream.Printf("%s(%ld) ", name, (long)m_id);
|
|
}
|
|
#endif
|
|
|
|
// CEditCommandLog
|
|
|
|
// We were having problems where we were entering a command while processing the undo of another command.
|
|
// This would cause the command log to be trimmed, which would delete the undo log, including the
|
|
// command that was being undone. This helps detect that situation.
|
|
|
|
#ifdef DEBUG
|
|
|
|
class CEditCommandLogRecursionCheckEntry {
|
|
private:
|
|
XP_Bool m_bOldBusy;
|
|
CEditCommandLog* m_log;
|
|
public:
|
|
CEditCommandLogRecursionCheckEntry(CEditCommandLog* log) {
|
|
m_log = log;
|
|
m_bOldBusy = m_log->m_bBusy;
|
|
XP_ASSERT(m_log->m_bBusy == FALSE);
|
|
m_log->m_bBusy = TRUE;
|
|
}
|
|
~CEditCommandLogRecursionCheckEntry() {
|
|
m_log->m_bBusy = m_bOldBusy;
|
|
}
|
|
};
|
|
|
|
#define DEBUG_RECURSION_CHECK CEditCommandLogRecursionCheckEntry debugRecursionCheckEntry(this);
|
|
#else
|
|
#define DEBUG_RECURSION_CHECK
|
|
#endif
|
|
|
|
CGlobalHistoryGroup* CGlobalHistoryGroup::g_pGlobalHistoryGroup;
|
|
|
|
CGlobalHistoryGroup* CGlobalHistoryGroup::GetGlobalHistoryGroup(){
|
|
if ( g_pGlobalHistoryGroup == NULL ) {
|
|
g_pGlobalHistoryGroup = new CGlobalHistoryGroup();
|
|
}
|
|
return g_pGlobalHistoryGroup;
|
|
}
|
|
|
|
CGlobalHistoryGroup::CGlobalHistoryGroup(){
|
|
m_pHead = NULL;
|
|
}
|
|
|
|
CGlobalHistoryGroup::~CGlobalHistoryGroup(){
|
|
CEditCommandLog* pLog = m_pHead;
|
|
while(pLog){
|
|
CEditCommandLog* pCurrent = pLog;
|
|
pLog = pLog->m_pNext;
|
|
delete pCurrent;
|
|
}
|
|
m_pHead = NULL;
|
|
}
|
|
|
|
XP_Bool CGlobalHistoryGroup::IsReload(CEditBuffer* pEditBuffer){
|
|
CEditCommandLog* pLog = m_pHead;
|
|
while(pLog){
|
|
if ( pEditBuffer->m_pContext == pLog->m_pContext ) {
|
|
return TRUE;
|
|
}
|
|
pLog = pLog->m_pNext;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
CEditCommandLog* CGlobalHistoryGroup::CreateLog(CEditBuffer* pEditBuffer){
|
|
CEditCommandLog* pLog = m_pHead;
|
|
while(pLog){
|
|
if ( pEditBuffer->m_pContext == pLog->m_pContext ) {
|
|
pLog->m_bIgnoreDelete = FALSE;
|
|
pLog->m_pBuffer = pEditBuffer;
|
|
return pLog;
|
|
}
|
|
pLog = pLog->m_pNext;
|
|
}
|
|
pLog = new CEditCommandLog();
|
|
pLog->m_pContext = pEditBuffer->m_pContext;
|
|
pLog->m_pNext = m_pHead;
|
|
pLog->m_pBuffer = pEditBuffer;
|
|
m_pHead = pLog;
|
|
return pLog;
|
|
}
|
|
|
|
CEditCommandLog* CGlobalHistoryGroup::GetLog(CEditBuffer* pEditBuffer){
|
|
CEditCommandLog* pLog = m_pHead;
|
|
while(pLog){
|
|
if ( pEditBuffer->m_pContext == pLog->m_pContext ) {
|
|
return pLog;
|
|
}
|
|
pLog = pLog->m_pNext;
|
|
}
|
|
XP_ASSERT(FALSE);
|
|
return NULL;
|
|
}
|
|
|
|
void CGlobalHistoryGroup::DeleteLog(CEditBuffer* pEditBuffer){
|
|
CEditCommandLog* pLog = m_pHead;
|
|
CEditCommandLog* pPrev = NULL;
|
|
while(pLog){
|
|
if ( pEditBuffer->m_pContext == pLog->m_pContext ) {
|
|
pLog->m_pBuffer = NULL;
|
|
if ( pLog->m_bIgnoreDelete ) {
|
|
pLog->m_bIgnoreDelete = FALSE;
|
|
}
|
|
else {
|
|
CEditCommandLog* pNext = pLog->m_pNext;
|
|
delete pLog;
|
|
if ( pPrev ) {
|
|
pPrev->m_pNext = pNext;
|
|
}
|
|
else {
|
|
m_pHead = pNext;
|
|
if ( pNext == NULL ) {
|
|
// Why yes, that is our this pointer....
|
|
delete g_pGlobalHistoryGroup;
|
|
g_pGlobalHistoryGroup = NULL;
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
pPrev = pLog;
|
|
pLog = pLog->m_pNext;
|
|
}
|
|
XP_ASSERT(FALSE);
|
|
}
|
|
|
|
void CGlobalHistoryGroup::IgnoreNextDeleteOf(CEditBuffer* pEditBuffer){
|
|
CEditCommandLog* pLog = GetLog(pEditBuffer);
|
|
if ( pLog ) {
|
|
XP_ASSERT(pLog->m_bIgnoreDelete == FALSE);
|
|
pLog->m_bIgnoreDelete = TRUE;
|
|
}
|
|
}
|
|
|
|
CCommandState::CCommandState(){
|
|
m_commandID = kNullCommandID;
|
|
m_pState = NULL;
|
|
}
|
|
|
|
CCommandState::~CCommandState(){
|
|
Flush();
|
|
}
|
|
|
|
void CCommandState::SetID(intn commandID){
|
|
m_commandID = commandID;
|
|
}
|
|
|
|
intn CCommandState::GetID(){
|
|
return m_commandID;
|
|
}
|
|
|
|
void CCommandState::Record(CEditBuffer* pBufferToRecord){
|
|
Flush();
|
|
m_pState = pBufferToRecord->RecordState();
|
|
}
|
|
|
|
void CCommandState::Restore(CEditBuffer* pBufferToRestore){
|
|
if (m_pState) {
|
|
pBufferToRestore->RestoreState(m_pState);
|
|
}
|
|
}
|
|
|
|
void CCommandState::Flush(){
|
|
delete m_pState;
|
|
m_pState = NULL;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
void CCommandState::Print(IStreamOut& stream) {
|
|
if (m_pState) {
|
|
stream.Printf("id: %d, ", m_commandID);
|
|
m_pState->Print(stream);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
CEditCommandLog::CEditCommandLog()
|
|
{
|
|
m_pBuffer = NULL;
|
|
m_pUndo = NULL;
|
|
m_pRedo = NULL;
|
|
m_iBatchLevel = 0;
|
|
m_pNext = NULL;
|
|
m_pContext = NULL;
|
|
m_bIgnoreDelete = FALSE;
|
|
#ifdef DEBUG
|
|
m_bBusy = FALSE;
|
|
#endif
|
|
m_state = 0;
|
|
m_version = 0;
|
|
m_storedVersion = 0;
|
|
m_highestVersion = 0;
|
|
#ifdef EDITOR_JAVA
|
|
m_pPlugins = 0;
|
|
#endif
|
|
m_pDocTempDir = NULL;
|
|
m_iDocTempFilenameNonce = 1;
|
|
|
|
|
|
// If this is the first CEditBuffer created, delete any
|
|
// temporary document directories from the last time
|
|
// Communicator 4.0 was run.
|
|
#if defined(XP_WIN) || defined(XP_MAC) || defined(XP_OS2)
|
|
// Don't do this for UNIX since multiple instances of Communicator
|
|
// may be running.
|
|
|
|
// First instance of CEditCommandLog.
|
|
if (m_iDocTempDirNonce == 0) {
|
|
m_iDocTempDirNonce++; // First temp dir will start with "1".
|
|
char *pxpURL = GetAppTempDir();
|
|
if (pxpURL) {
|
|
// recursive delete.
|
|
edt_RemoveDirectoryR(pxpURL);
|
|
XP_FREE(pxpURL);
|
|
}
|
|
else {
|
|
XP_ASSERT(0);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
CEditCommandLog::~CEditCommandLog()
|
|
{
|
|
Trim();
|
|
#ifdef EDITOR_JAVA
|
|
EditorPluginManager_delete(m_pPlugins);
|
|
m_pPlugins = 0;
|
|
#endif
|
|
|
|
// Clean up the temp files associated with this doc.
|
|
if (m_pDocTempDir) {
|
|
edt_RemoveDirectoryR(m_pDocTempDir);
|
|
XP_FREE(m_pDocTempDir);
|
|
}
|
|
|
|
}
|
|
|
|
void CEditCommandLog::StartTyping(intn typing){
|
|
InternalDo(typing);
|
|
}
|
|
|
|
void CEditCommandLog::EndTyping(){
|
|
}
|
|
|
|
void CEditCommandLog::AdoptAndDo(CEditCommand* pCommand)
|
|
{
|
|
DEBUG_RECURSION_CHECK
|
|
|
|
if ( m_iBatchLevel == 0 ){
|
|
InternalAdoptAndDo(pCommand);
|
|
}
|
|
else
|
|
{
|
|
pCommand->Do();
|
|
delete pCommand;
|
|
}
|
|
}
|
|
|
|
void CEditCommandLog::InternalAdoptAndDo(CEditCommand* command)
|
|
{
|
|
InternalDo(command->GetID());
|
|
command->Do();
|
|
delete command;
|
|
}
|
|
|
|
void CEditCommandLog::InternalDo(intn id)
|
|
{
|
|
if ( m_state == 1 ) {
|
|
// recovering from an undo/redo
|
|
return;
|
|
}
|
|
delete m_pUndo;
|
|
m_pUndo = new CCommandState();
|
|
m_pUndo->SetID(id);
|
|
m_pUndo->Record(m_pBuffer);
|
|
|
|
if ( m_pRedo ) {
|
|
delete m_pRedo;
|
|
m_pRedo = NULL;
|
|
}
|
|
m_state = 0;
|
|
|
|
// Set m_version to a version that has never been seen before.
|
|
m_version = ++m_highestVersion;
|
|
}
|
|
|
|
void CEditCommandLog::Undo()
|
|
{
|
|
DEBUG_RECURSION_CHECK
|
|
if ( !m_pUndo ) {
|
|
XP_TRACE(("Nothing to undo."));
|
|
return;
|
|
}
|
|
if ( m_pUndo )
|
|
{
|
|
FinishBatchCommands();
|
|
if ( ! m_pRedo ) {
|
|
m_pRedo = new CCommandState();
|
|
m_pRedo->SetID(m_pUndo->GetID());
|
|
m_pRedo->Record(m_pBuffer);
|
|
}
|
|
m_pUndo->Restore(m_pBuffer);
|
|
delete m_pUndo;
|
|
m_pUndo = NULL;
|
|
}
|
|
m_state = 1;
|
|
// CCommandState::Restore() will set m_version.
|
|
}
|
|
|
|
void CEditCommandLog::Redo()
|
|
{
|
|
DEBUG_RECURSION_CHECK
|
|
if ( !m_pRedo ) {
|
|
XP_TRACE(("Nothing to redo."));
|
|
return;
|
|
}
|
|
if ( m_pRedo )
|
|
{
|
|
FinishBatchCommands();
|
|
if ( ! m_pUndo ) {
|
|
m_pUndo = new CCommandState();
|
|
m_pUndo->SetID(m_pRedo->GetID());
|
|
m_pUndo->Record(m_pBuffer);
|
|
}
|
|
m_pRedo->Restore(m_pBuffer);
|
|
delete m_pRedo;
|
|
m_pRedo = NULL;
|
|
}
|
|
m_state = 1;
|
|
// CCommandState::Restore() will set m_version.
|
|
}
|
|
|
|
void CEditCommandLog::FinishBatchCommands()
|
|
{
|
|
if ( m_iBatchLevel > 0 ){
|
|
XP_ASSERT(FALSE);
|
|
m_iBatchLevel = 0;
|
|
}
|
|
}
|
|
|
|
void CEditCommandLog::Trim()
|
|
{
|
|
delete m_pRedo;
|
|
m_pRedo = NULL;
|
|
delete m_pUndo;
|
|
m_pUndo = NULL;
|
|
}
|
|
|
|
XP_Bool CEditCommandLog::InReload(){
|
|
return m_state != 0;
|
|
}
|
|
void CEditCommandLog::SetInReload(XP_Bool bInReload){
|
|
m_state = bInReload;
|
|
}
|
|
|
|
XP_Bool CEditCommandLog::IsDirty(){
|
|
return m_version != m_storedVersion;
|
|
}
|
|
|
|
DocumentVersion CEditCommandLog::GetVersion(){
|
|
return m_version;
|
|
}
|
|
|
|
void CEditCommandLog::SetVersion(DocumentVersion version) {
|
|
m_version = version;
|
|
}
|
|
|
|
void CEditCommandLog::DocumentStored(){
|
|
m_storedVersion = m_version;
|
|
}
|
|
|
|
DocumentVersion CEditCommandLog::GetStoredVersion(){
|
|
return m_storedVersion;
|
|
}
|
|
|
|
intn CEditCommandLog::GetCommandHistoryLimit()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
void CEditCommandLog::SetCommandHistoryLimit(intn newLimit) {
|
|
if ( newLimit >= 0 ) {
|
|
Trim();
|
|
}
|
|
}
|
|
|
|
intn CEditCommandLog::GetNumberOfCommandsToUndo()
|
|
{
|
|
return m_pUndo ? 1 : 0;
|
|
}
|
|
|
|
intn CEditCommandLog::GetNumberOfCommandsToRedo()
|
|
{
|
|
return m_pRedo ? 1 : 0;
|
|
}
|
|
|
|
// Returns NULL if out of range
|
|
intn CEditCommandLog::GetUndoCommand(intn index)
|
|
{
|
|
if ( m_pUndo == NULL || index < 0 || index >= GetNumberOfCommandsToUndo())
|
|
return kNullCommandID;
|
|
return m_pUndo->GetID();
|
|
}
|
|
|
|
intn CEditCommandLog::GetRedoCommand(intn index)
|
|
{
|
|
if ( m_pRedo == NULL || index < 0 || index >= GetNumberOfCommandsToRedo() )
|
|
return kNullCommandID;
|
|
return m_pRedo->GetID();
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
void CEditCommandLog::Print(IStreamOut& stream) {
|
|
stream.Printf("state: %d\n", m_state);
|
|
stream.Printf("Undo list: %d commands\n", GetNumberOfCommandsToUndo());
|
|
if ( m_pUndo ) {
|
|
m_pUndo->Print(stream);
|
|
}
|
|
stream.Printf("Redo list: %d commands\n", GetNumberOfCommandsToRedo());
|
|
if ( m_pRedo ) {
|
|
m_pRedo->Print(stream);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void CEditCommandLog::BeginBatchChanges(intn id) {
|
|
if ( m_iBatchLevel < 0 ) {
|
|
XP_ASSERT(FALSE);
|
|
m_iBatchLevel = 0;
|
|
}
|
|
if ( m_iBatchLevel++ == 0 ) {
|
|
InternalDo(id);
|
|
}
|
|
}
|
|
|
|
void CEditCommandLog::EndBatchChanges() {
|
|
if(m_iBatchLevel <= 0) {
|
|
XP_ASSERT(FALSE);
|
|
m_iBatchLevel = 0;
|
|
}
|
|
else {
|
|
m_iBatchLevel--;
|
|
}
|
|
}
|
|
|
|
#ifdef EDITOR_JAVA
|
|
EditorPluginManager CEditCommandLog::GetPlugins(){
|
|
if ( m_pPlugins == NULL ) {
|
|
m_pPlugins = EditorPluginManager_new(m_pContext);
|
|
}
|
|
return m_pPlugins;
|
|
}
|
|
#endif
|
|
|
|
// Returns xpURL, ends in slash.
|
|
char *CEditCommandLog::GetAppTempDir() {
|
|
char *pTempRoot = XP_TempDirName();
|
|
char* pTempURL = XP_PlatformFileToURL(pTempRoot);
|
|
XP_FREEIF(pTempRoot);
|
|
if (!(pTempURL && *pTempURL)) {
|
|
XP_ASSERT(0);
|
|
return NULL;
|
|
}
|
|
// Make sure ends in slash.
|
|
if (pTempURL[XP_STRLEN(pTempURL)-1] != '/') {
|
|
StrAllocCat(pTempURL,"/");
|
|
}
|
|
|
|
// Will still end in a slash.
|
|
#ifdef XP_UNIX
|
|
// NOTE: on UNIX we need to provide support for multiple users...
|
|
//
|
|
char *pUserName = getenv("USER");
|
|
|
|
if (pUserName != NULL) {
|
|
StrAllocCat(pTempURL,"nscomm40-");
|
|
StrAllocCat(pTempURL,pUserName);
|
|
StrAllocCat(pTempURL,"/");
|
|
}
|
|
else {
|
|
StrAllocCat(pTempURL,"nscomm40/");
|
|
}
|
|
#else
|
|
StrAllocCat(pTempURL,"nscomm40/");
|
|
#endif
|
|
// pTempURL is now the application temp dir root.
|
|
|
|
// EXTREME DANGER! CANNOT USE THIS IF "#" IS IN THE TEMP DIRECTORY NAME!
|
|
// Bug 83166 -- entire C drive deleted if TEMP=C:\#TEMP
|
|
|
|
//char *pTemp_xpURL = NET_ParseURL(pTempURL,GET_PATH_PART);
|
|
|
|
// This is (mostly) lifted from NET_ParseURL - just skip over host part
|
|
char *pTemp_xpURL = NULL;
|
|
char * colon = XP_STRCHR(pTempURL, ':'); /* returns a const char */
|
|
if(colon)
|
|
{
|
|
char * slash;
|
|
if(*(colon+1) == '/' && *(colon+2) == '/')
|
|
{
|
|
/* skip host part */
|
|
slash = XP_STRCHR(colon+3, '/');
|
|
}
|
|
else
|
|
{
|
|
/* path is right after the colon
|
|
*/
|
|
slash = colon+1;
|
|
}
|
|
// Copy everything starting with "/" to result string
|
|
pTemp_xpURL = XP_STRDUP(slash);
|
|
XP_FREEIF(pTempURL);
|
|
|
|
} else {
|
|
// Should never get here, but if no colon,
|
|
// just return what we started with
|
|
pTemp_xpURL = pTempURL;
|
|
}
|
|
|
|
return pTemp_xpURL;
|
|
}
|
|
|
|
char *CEditCommandLog::GetDocTempDir() {
|
|
// Already created.
|
|
if (m_pDocTempDir) {
|
|
return XP_STRDUP(m_pDocTempDir);
|
|
}
|
|
|
|
char *pTemp_xpURL = GetAppTempDir();
|
|
if (!pTemp_xpURL) {
|
|
XP_ASSERT(0);
|
|
return NULL;
|
|
}
|
|
|
|
// Create application temporary directory if necessary
|
|
XP_Dir pDir = edt_OpenDir(pTemp_xpURL,xpURL);
|
|
if (pDir) {
|
|
// Already exists, so ok.
|
|
XP_CloseDir(pDir);
|
|
}
|
|
else {
|
|
edt_MakeDirectory(pTemp_xpURL,xpURL);
|
|
pDir = edt_OpenDir(pTemp_xpURL,xpURL);
|
|
if (pDir) {
|
|
// made successfully, ok
|
|
XP_CloseDir(pDir);
|
|
}
|
|
else {
|
|
// can't make it, so fail.
|
|
XP_FREEIF(pTemp_xpURL);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
// Under application temporary directory, create process-specific
|
|
// temporary directory. This is only really process-specific for
|
|
// UNIX. WIN and MAC has dummy directory name.
|
|
char *pProcessDir = NULL;
|
|
#ifdef XP_UNIX
|
|
pProcessDir = PR_smprintf("%u/",(unsigned)getpid());
|
|
#else
|
|
pProcessDir = XP_STRDUP("tmp/");
|
|
#endif
|
|
StrAllocCat(pTemp_xpURL,pProcessDir);
|
|
if (!pTemp_xpURL || !pProcessDir) {
|
|
XP_ASSERT(0);
|
|
XP_FREEIF(pProcessDir);
|
|
XP_FREEIF(pTemp_xpURL);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
// pTemp_xpURL now has process-specific name appended.
|
|
pDir = edt_OpenDir(pTemp_xpURL,xpURL);
|
|
if (pDir) {
|
|
// Already exists, so ok.
|
|
XP_CloseDir(pDir);
|
|
}
|
|
else {
|
|
edt_MakeDirectory(pTemp_xpURL,xpURL);
|
|
pDir = edt_OpenDir(pTemp_xpURL,xpURL);
|
|
if (pDir) {
|
|
// made successfully, ok
|
|
XP_CloseDir(pDir);
|
|
}
|
|
else {
|
|
// can't make it, so fail.
|
|
XP_FREEIF(pTemp_xpURL);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
// Create document-specific temp dir.
|
|
char *pFilename = PR_smprintf("tmp%ld",m_iDocTempDirNonce);
|
|
if (!pFilename) {
|
|
XP_ASSERT(0);
|
|
XP_FREE(pTemp_xpURL);
|
|
return NULL;
|
|
}
|
|
if (XP_STRLEN(pFilename) > 8) {
|
|
// truncate at 8 chars.
|
|
pFilename[8] = '\0';
|
|
}
|
|
StrAllocCat(pTemp_xpURL,pFilename);
|
|
XP_FREE(pFilename);
|
|
|
|
// end in slash.
|
|
StrAllocCat(pTemp_xpURL,"/");
|
|
|
|
pDir = edt_OpenDir(pTemp_xpURL,xpURL);
|
|
if (pDir) {
|
|
// Already exists. Strange, but not really an error.
|
|
XP_CloseDir(pDir);
|
|
}
|
|
else {
|
|
edt_MakeDirectory(pTemp_xpURL,xpURL);
|
|
pDir = edt_OpenDir(pTemp_xpURL,xpURL);
|
|
if (pDir) {
|
|
// made successfully, ok
|
|
XP_CloseDir(pDir);
|
|
}
|
|
else {
|
|
// failure, clear pTemp_xpURL
|
|
XP_FREEIF(pTemp_xpURL);
|
|
}
|
|
}
|
|
|
|
if (pTemp_xpURL) {
|
|
// success.
|
|
m_iDocTempDirNonce++;
|
|
m_pDocTempDir = pTemp_xpURL;
|
|
return XP_STRDUP(m_pDocTempDir);
|
|
}
|
|
else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
int32 CEditCommandLog::m_iDocTempDirNonce = 0;
|
|
|
|
|
|
// Always return a new filename in the temporary directory.
|
|
char *CEditCommandLog::CreateDocTempFilename(char *pPrefix,char *pExtension) {
|
|
// Add directory.
|
|
char *pTempF = GetDocTempDir();
|
|
if (!pTempF) {
|
|
return NULL;
|
|
}
|
|
|
|
// Add file prefix.
|
|
if (pPrefix) {
|
|
char *pPreCopy = XP_STRDUP(pPrefix);
|
|
if (!pPreCopy) {
|
|
XP_ASSERT(0);
|
|
return NULL;
|
|
}
|
|
|
|
// truncate to 3 chars.
|
|
if (XP_STRLEN(pPreCopy) > 3) {
|
|
pPreCopy[3] = '\0';
|
|
}
|
|
|
|
StrAllocCat(pTempF,pPreCopy);
|
|
XP_FREE(pPreCopy);
|
|
}
|
|
else {
|
|
// default to "edt" for prefix.
|
|
StrAllocCat(pTempF,"edt");
|
|
}
|
|
|
|
if (!pTempF) {
|
|
return NULL;
|
|
}
|
|
|
|
char *pTempFilename = PR_smprintf("%s%d.%s",
|
|
pTempF,
|
|
(int)m_iDocTempFilenameNonce,
|
|
(pExtension ? pExtension : "tmp"));
|
|
XP_FREE(pTempF);
|
|
m_iDocTempFilenameNonce++;
|
|
return pTempFilename;
|
|
}
|
|
|
|
|
|
// CEditDataSaver
|
|
|
|
CEditDataSaver::CEditDataSaver(CEditBuffer* pBuffer){
|
|
m_pEditBuffer = pBuffer;
|
|
m_bModifiedTextHasBeenSaved = FALSE;
|
|
#ifdef DEBUG
|
|
m_bDoState = 0;
|
|
#endif
|
|
}
|
|
|
|
CEditDataSaver::~CEditDataSaver(){
|
|
}
|
|
|
|
void CEditDataSaver::DoBegin(CPersistentEditSelection& original){
|
|
#ifdef DEBUG
|
|
XP_ASSERT(m_bDoState == 0);
|
|
m_bDoState++;
|
|
#endif
|
|
m_original = original;
|
|
m_pEditBuffer->GetSelection(m_originalDocument);
|
|
CEditSelection selection =
|
|
m_pEditBuffer->PersistentToEphemeral(m_original);
|
|
selection.ExpandToNotCrossStructures();
|
|
m_expandedOriginal = m_pEditBuffer->EphemeralToPersistent(selection);
|
|
m_pEditBuffer->CopyEditText(m_expandedOriginal, m_originalText);
|
|
}
|
|
|
|
void CEditDataSaver::DoEnd(CPersistentEditSelection& modified){
|
|
#ifdef DEBUG
|
|
XP_ASSERT(m_bDoState == 1);
|
|
m_bDoState++;
|
|
#endif
|
|
m_pEditBuffer->GetSelection(m_modifiedDocument);
|
|
m_expandedModified = m_expandedOriginal;
|
|
m_expandedModified.Map(m_original, modified);
|
|
}
|
|
|
|
void CEditDataSaver::Undo(){
|
|
#ifdef DEBUG
|
|
XP_ASSERT(m_bDoState == 2);
|
|
m_bDoState++;
|
|
#endif
|
|
m_pEditBuffer->SetSelection(m_expandedModified);
|
|
if ( ! m_bModifiedTextHasBeenSaved ) {
|
|
m_pEditBuffer->CutEditText(m_modifiedText);
|
|
m_bModifiedTextHasBeenSaved = TRUE;
|
|
}
|
|
else {
|
|
m_pEditBuffer->DeleteSelection();
|
|
}
|
|
m_pEditBuffer->PasteEditText(m_originalText);
|
|
m_pEditBuffer->SetSelection(m_originalDocument);
|
|
}
|
|
|
|
void CEditDataSaver::Redo(){
|
|
#ifdef DEBUG
|
|
XP_ASSERT(m_bDoState == 3);
|
|
m_bDoState--;
|
|
#endif
|
|
m_pEditBuffer->SetSelection(m_expandedOriginal);
|
|
m_pEditBuffer->DeleteSelection();
|
|
m_pEditBuffer->PasteEditText(m_modifiedText);
|
|
m_pEditBuffer->SetSelection(m_modifiedDocument);
|
|
}
|
|
|
|
|
|
// CDeleteTableCommand
|
|
CDeleteTableCommand::CDeleteTableCommand(CEditBuffer* pBuffer, intn id)
|
|
: CEditCommand(pBuffer, id)
|
|
{
|
|
m_pTable = NULL;
|
|
pBuffer->GetSelection(m_originalSelection);
|
|
CEditInsertPoint ip;
|
|
pBuffer->GetTableInsertPoint(ip);
|
|
pBuffer->ClearTableAndCellSelection();
|
|
m_pTable = ip.m_pElement->GetTableIgnoreSubdoc();
|
|
if ( m_pTable )
|
|
m_pTable->Delete();
|
|
}
|
|
|
|
CDeleteTableCommand::~CDeleteTableCommand()
|
|
{
|
|
// Now done in CEditTableElement::Delete()
|
|
// delete m_pTable;
|
|
}
|
|
|
|
void CDeleteTableCommand::Do() {
|
|
}
|
|
|
|
// CInsertTableCaptionCommand
|
|
CInsertTableCaptionCommand::CInsertTableCaptionCommand(CEditBuffer* pBuffer,
|
|
EDT_TableCaptionData* pData, intn id)
|
|
: CEditCommand(pBuffer, id)
|
|
{
|
|
m_pOldCaption = NULL;
|
|
pBuffer->GetSelection(m_originalSelection);
|
|
CEditInsertPoint ip;
|
|
pBuffer->GetTableInsertPoint(ip);
|
|
CEditTableElement* pTable = ip.m_pElement->GetTableIgnoreSubdoc();
|
|
if ( pTable )
|
|
{
|
|
CEditCaptionElement* pCaption = new CEditCaptionElement();
|
|
pCaption->SetData(pData);
|
|
pTable->SetCaption(pCaption);
|
|
pTable->FinishedLoad(pBuffer);
|
|
// CLM: Don't move insert point if we have a selected cell
|
|
// (We use selection to indicate current cell in property dialogs)
|
|
if( !pBuffer->IsSelected() &&
|
|
ip.m_pElement->GetTableCellIgnoreSubdoc() != NULL )
|
|
{
|
|
// Put cursor at end of caption
|
|
ip.m_pElement = pTable->GetCaption()->GetLastMostChild()->Leaf();
|
|
ip.m_iPos = ip.m_pElement->GetLen();
|
|
pBuffer->SetInsertPoint(ip);
|
|
}
|
|
pBuffer->Relayout(pTable, 0);
|
|
}
|
|
}
|
|
|
|
CInsertTableCaptionCommand::~CInsertTableCaptionCommand()
|
|
{
|
|
delete m_pOldCaption;
|
|
}
|
|
|
|
void CInsertTableCaptionCommand::Do() {
|
|
// All done in constructor
|
|
}
|
|
|
|
// CDeleteTableCaptionCommand
|
|
CDeleteTableCaptionCommand::CDeleteTableCaptionCommand(CEditBuffer* pBuffer, intn id)
|
|
: CEditCommand(pBuffer, id),
|
|
m_pOldCaption(NULL)
|
|
{
|
|
pBuffer->GetSelection(m_originalSelection);
|
|
CEditInsertPoint ip;
|
|
pBuffer->GetTableInsertPoint(ip);
|
|
CEditTableElement* pTable = ip.m_pElement->GetTableIgnoreSubdoc();
|
|
if ( pTable )
|
|
{
|
|
m_pOldCaption = pTable->GetCaption();
|
|
if ( m_pOldCaption )
|
|
{
|
|
CEditTableCellElement* pTableCell = ip.m_pElement->GetTableCellIgnoreSubdoc();
|
|
//cmanske - Set cursor only if we are not in the caption being deleted
|
|
CEditCaptionElement *pCaption = ip.m_pElement->GetCaption();
|
|
|
|
m_pOldCaption->Unlink();
|
|
pTable->FinishedLoad(pBuffer);
|
|
if( pCaption /*!pTableCell*/ )
|
|
{
|
|
// Set cursor to someplace that still exists
|
|
// TODO: NEED TO FIX THIS TO PLACE CURSOR CLOSER TO WHERE CAPTION WAS
|
|
CEditTableCellElement * pCell = pTable->GetFirstCell();
|
|
int32 X = 0;
|
|
int32 Y = 0;
|
|
if( pCell )
|
|
{
|
|
X = pCell->GetX();
|
|
Y = pCell->GetY();
|
|
}
|
|
pBuffer->StartSelection(X,Y);
|
|
}
|
|
pBuffer->Relayout(pTable, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
CDeleteTableCaptionCommand::~CDeleteTableCaptionCommand()
|
|
{
|
|
delete m_pOldCaption;
|
|
}
|
|
|
|
void CDeleteTableCaptionCommand::Do()
|
|
{
|
|
}
|
|
|
|
// CInsertTableRowCommand
|
|
CInsertTableRowCommand::CInsertTableRowCommand(CEditBuffer* pBuffer,
|
|
EDT_TableRowData* /* pData */, XP_Bool bAfterCurrentRow, intn number, intn id)
|
|
: CEditCommand(pBuffer, id)
|
|
{
|
|
m_number = number;
|
|
pBuffer->GetSelection(m_originalSelection);
|
|
if( pBuffer->IsSelected() )
|
|
{
|
|
pBuffer->ClearSelection();
|
|
}
|
|
CEditInsertPoint ip;
|
|
pBuffer->GetTableInsertPoint(ip);
|
|
CEditTableCellElement* pTableCell = ip.m_pElement->GetTableCellIgnoreSubdoc();
|
|
if ( pTableCell)
|
|
{
|
|
CEditTableElement* pTable = pTableCell->GetTable();
|
|
if ( pTable )
|
|
{
|
|
int32 Y = pTableCell->GetY();
|
|
int32 iNewY = Y + (bAfterCurrentRow ? pTableCell->GetHeight() : 0);
|
|
pBuffer->m_pCellForInsertPoint = 0;
|
|
pTable->InsertRows(Y, iNewY, number, NULL, 0, &pBuffer->m_pCellForInsertPoint);
|
|
pTable->FinishedLoad(pBuffer);
|
|
pBuffer->Relayout(pTable, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
CInsertTableRowCommand::~CInsertTableRowCommand()
|
|
{
|
|
}
|
|
|
|
void CInsertTableRowCommand::Do() {
|
|
// All done in constructor
|
|
}
|
|
|
|
|
|
// CDeleteTableRowCommand
|
|
CDeleteTableRowCommand::CDeleteTableRowCommand(CEditBuffer* pBuffer, intn rows, XP_Bool *pTableDeleted, intn id)
|
|
: CEditCommand(pBuffer, id),
|
|
m_table(0,0)
|
|
{
|
|
pBuffer->GetSelection(m_originalSelection);
|
|
//The code from Redo moved here:
|
|
CEditInsertPoint ip;
|
|
pBuffer->GetTableInsertPoint(ip);
|
|
CEditTableCellElement* pTableCell = ip.m_pElement->GetTableCellIgnoreSubdoc();
|
|
if ( pTableCell )
|
|
{
|
|
CEditTableElement* pTable = pTableCell->GetTable();
|
|
if ( pTable )
|
|
{
|
|
int32 Y = pTableCell->GetY();
|
|
pBuffer->m_pCellForInsertPoint = 0;
|
|
// Get elements before and after the table
|
|
CEditElement *pLeafBefore = pTable->PreviousLeaf();
|
|
XP_ASSERT(pLeafBefore);
|
|
CEditElement *pLeafAfter = pTable->GetLastMostChild();
|
|
if( pLeafAfter )
|
|
pLeafAfter = pLeafAfter->NextLeaf();
|
|
|
|
pTable->DeleteRows(Y, rows, &pBuffer->m_pCellForInsertPoint);
|
|
pTable->FinishedLoad(pBuffer);
|
|
|
|
if( pBuffer->m_pCellForInsertPoint == NULL )
|
|
{
|
|
// Move to a safe location so Relayout() doesn't assert
|
|
if( pLeafBefore )
|
|
pBuffer->SetInsertPoint(pLeafBefore->Leaf(), 0, pBuffer->m_bCurrentStickyAfter);
|
|
}
|
|
// Check if all rows were deleted
|
|
if( pTable->CountRows() == 0 )
|
|
{
|
|
// Move any caption contents so they will display
|
|
pTable->MoveCaptionOutsideTable(pLeafBefore == 0);
|
|
// Delete the table
|
|
pTable->Unlink();
|
|
delete pTable;
|
|
if( pTableDeleted )
|
|
*pTableDeleted = TRUE;
|
|
}
|
|
else if( pTableDeleted )
|
|
*pTableDeleted = FALSE;
|
|
|
|
pBuffer->Relayout(pLeafBefore, 0, pLeafAfter, RELAYOUT_NOCARET);
|
|
}
|
|
}
|
|
}
|
|
|
|
CDeleteTableRowCommand::~CDeleteTableRowCommand()
|
|
{
|
|
}
|
|
|
|
void CDeleteTableRowCommand::Do()
|
|
{
|
|
// All done in constructor
|
|
}
|
|
|
|
|
|
// CInsertTableColumnCommand
|
|
CInsertTableColumnCommand::CInsertTableColumnCommand(CEditBuffer* pBuffer,
|
|
EDT_TableCellData* /* pData */, XP_Bool bAfterCurrentCell, intn number, intn id)
|
|
: CEditCommand(pBuffer, id)
|
|
{
|
|
// m_number = number;
|
|
pBuffer->GetSelection(m_originalSelection);
|
|
if( pBuffer->IsSelected() ){
|
|
pBuffer->ClearSelection();
|
|
}
|
|
CEditInsertPoint ip;
|
|
pBuffer->GetTableInsertPoint(ip);
|
|
CEditTableCellElement* pTableCell = ip.m_pElement->GetTableCellIgnoreSubdoc();
|
|
if ( pTableCell)
|
|
{
|
|
CEditTableElement* pTable = pTableCell->GetTable();
|
|
if ( pTable )
|
|
{
|
|
int32 X = pTableCell->GetX();
|
|
int32 iNewX = X + (bAfterCurrentCell ? pTableCell->GetFullWidth() : 0); // WAS GetWidth()
|
|
pBuffer->m_pCellForInsertPoint = 0;
|
|
pTable->InsertColumns(X, iNewX, number, NULL, 0, &pBuffer->m_pCellForInsertPoint);
|
|
pTable->FinishedLoad(pBuffer);
|
|
pBuffer->Relayout(pTable, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
CInsertTableColumnCommand::~CInsertTableColumnCommand()
|
|
{
|
|
}
|
|
|
|
void CInsertTableColumnCommand::Do() {
|
|
// All done in constructor
|
|
}
|
|
|
|
// CDeleteTableColumnCommand
|
|
CDeleteTableColumnCommand::CDeleteTableColumnCommand(CEditBuffer* pBuffer, intn columns, XP_Bool *pTableDeleted, intn id)
|
|
: CEditCommand(pBuffer, id),
|
|
m_table(0,0)
|
|
{
|
|
// m_columns = columns;
|
|
pBuffer->GetSelection(m_originalSelection);
|
|
CEditInsertPoint ip;
|
|
pBuffer->GetTableInsertPoint(ip);
|
|
CEditTableCellElement* pTableCell = ip.m_pElement->GetTableCellIgnoreSubdoc();
|
|
if ( pTableCell )
|
|
{
|
|
CEditTableElement* pTable = pTableCell->GetTable();
|
|
if ( pTable )
|
|
{
|
|
int32 X = pTableCell->GetX();
|
|
pBuffer->m_pCellForInsertPoint = 0;
|
|
|
|
CEditElement *pLeafBefore = pTable->PreviousLeaf();
|
|
XP_ASSERT(pLeafBefore);
|
|
CEditElement *pLeafAfter = pTable->GetLastMostChild();
|
|
if( pLeafAfter )
|
|
pLeafAfter = pLeafAfter->NextLeaf();
|
|
|
|
// We don't save the table to undo any more
|
|
pTable->DeleteColumns(X, columns, &pBuffer->m_pCellForInsertPoint );
|
|
|
|
if( pBuffer->m_pCellForInsertPoint == NULL )
|
|
{
|
|
// Move to a safe location so Relayout() doesn't assert
|
|
if( pLeafBefore )
|
|
pBuffer->SetInsertPoint(pLeafBefore->Leaf(), 0, pBuffer->m_bCurrentStickyAfter);
|
|
}
|
|
// Check if all rows were deleted
|
|
if( pTable->CountRows() == 0 )
|
|
{
|
|
// Move any caption contents so they will display
|
|
pTable->MoveCaptionOutsideTable(pLeafBefore == 0);
|
|
// Delete the table
|
|
pTable->Unlink();
|
|
delete pTable;
|
|
if( pTableDeleted )
|
|
*pTableDeleted = TRUE;
|
|
}
|
|
else if( pTableDeleted )
|
|
*pTableDeleted = FALSE;
|
|
|
|
pBuffer->Relayout(pLeafBefore, 0, pLeafAfter, RELAYOUT_NOCARET);
|
|
}
|
|
}
|
|
}
|
|
|
|
CDeleteTableColumnCommand::~CDeleteTableColumnCommand()
|
|
{
|
|
}
|
|
|
|
void CDeleteTableColumnCommand::Do()
|
|
{
|
|
//#endif
|
|
}
|
|
|
|
|
|
// CInsertTableCellCommand
|
|
CInsertTableCellCommand::CInsertTableCellCommand(CEditBuffer* pBuffer, XP_Bool bAfterCurrentCell,
|
|
intn number, intn id)
|
|
: CEditCommand(pBuffer, id)
|
|
{
|
|
m_number = number;
|
|
pBuffer->GetSelection(m_originalSelection);
|
|
if( pBuffer->IsSelected() ){
|
|
pBuffer->ClearSelection();
|
|
}
|
|
CEditInsertPoint ip;
|
|
pBuffer->GetTableInsertPoint(ip);
|
|
CEditTableCellElement* pTableCell = ip.m_pElement->GetTableCellIgnoreSubdoc();
|
|
if ( pTableCell)
|
|
{
|
|
CEditTableRowElement* pTableRow = pTableCell->GetTableRow();
|
|
CEditTableElement* pTable = pTableCell->GetTable();
|
|
if ( pTable && pTableRow )
|
|
{
|
|
int32 X = pTableCell->GetX();
|
|
int32 iNewX = X + (bAfterCurrentCell ? pTableCell->GetFullWidth() : 0); // WAS GetWidth()
|
|
pBuffer->m_pCellForInsertPoint = 0;
|
|
pTableRow->InsertCells(X, iNewX, number, NULL, &pBuffer->m_pCellForInsertPoint);
|
|
pTable->FinishedLoad(pBuffer);
|
|
pBuffer->Relayout(pTable, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
CInsertTableCellCommand::~CInsertTableCellCommand()
|
|
{
|
|
}
|
|
|
|
void CInsertTableCellCommand::Do() {
|
|
// All done in constructor
|
|
}
|
|
|
|
|
|
// CDeleteTableCellCommand
|
|
CDeleteTableCellCommand::CDeleteTableCellCommand(CEditBuffer* pBuffer, intn columns, XP_Bool *pTableDeleted, intn id)
|
|
: CEditCommand(pBuffer, id)
|
|
{
|
|
// m_columns = columns;
|
|
pBuffer->GetSelection(m_originalSelection);
|
|
CEditInsertPoint ip;
|
|
pBuffer->GetTableInsertPoint(ip);
|
|
CEditTableCellElement* pTableCell = ip.m_pElement->GetTableCellIgnoreSubdoc();
|
|
if ( pTableCell )
|
|
{
|
|
CEditTableRowElement* pTableRow = pTableCell->GetTableRowIgnoreSubdoc();
|
|
CEditTableElement* pTable = pTableCell->GetTableIgnoreSubdoc();
|
|
if ( pTable && pTableRow )
|
|
{
|
|
int32 X = pTableCell->GetX();
|
|
pBuffer->m_pCellForInsertPoint = 0;
|
|
|
|
CEditElement *pLeafBefore = pTable->PreviousLeaf();
|
|
XP_ASSERT(pLeafBefore);
|
|
CEditElement *pLeafAfter = pTable->GetLastMostChild();
|
|
if( pLeafAfter )
|
|
pLeafAfter = pLeafAfter->NextLeaf();
|
|
|
|
pTableRow->DeleteCells(X, columns, &pBuffer->m_pCellForInsertPoint);
|
|
pTable->FinishedLoad(pBuffer);
|
|
|
|
if( pBuffer->m_pCellForInsertPoint == NULL )
|
|
{
|
|
// Move to a safe location so Relayout() doesn't assert
|
|
CEditElement *pLeaf = pTable->FindPreviousElement(&CEditElement::FindLeafAll, 0 );
|
|
if( pLeaf )
|
|
pBuffer->SetInsertPoint(pLeaf->Leaf(), 0, pBuffer->m_bCurrentStickyAfter);
|
|
}
|
|
// Check if all rows were deleted
|
|
if( pTable->CountRows() == 0 )
|
|
{
|
|
// Move any caption contents so they will display
|
|
pTable->MoveCaptionOutsideTable(pLeafBefore == 0);
|
|
// Delete the table
|
|
pTable->Unlink();
|
|
delete pTable;
|
|
if( pTableDeleted )
|
|
*pTableDeleted = TRUE;
|
|
}
|
|
else if( pTableDeleted )
|
|
*pTableDeleted = FALSE;
|
|
|
|
pBuffer->Relayout(pLeafBefore, 0, pLeafAfter, RELAYOUT_NOCARET);
|
|
}
|
|
}
|
|
}
|
|
|
|
CDeleteTableCellCommand::~CDeleteTableCellCommand()
|
|
{
|
|
}
|
|
|
|
void CDeleteTableCellCommand::Do()
|
|
{
|
|
}
|
|
|
|
|
|
// CEditCommandGroup
|
|
|
|
CEditCommandGroup::CEditCommandGroup(CEditBuffer* pEditBuffer, int id)
|
|
: CEditCommand( pEditBuffer, id){
|
|
}
|
|
|
|
CEditCommandGroup::~CEditCommandGroup(){
|
|
for ( int i = 0; i < m_commands.Size(); i++ ) {
|
|
CEditCommand* item = m_commands[i];
|
|
delete item;
|
|
}
|
|
}
|
|
|
|
void CEditCommandGroup::AdoptAndDo(CEditCommand* pCommand){
|
|
pCommand->Do();
|
|
//TODO: IS THIS EVER FREED???
|
|
m_commands.Add(pCommand);
|
|
}
|
|
|
|
void CEditCommandGroup::Undo(){
|
|
for ( int i = m_commands.Size() - 1; i >= 0 ; i-- ) {
|
|
CEditCommand* item = m_commands[i];
|
|
item->Undo();
|
|
}
|
|
}
|
|
|
|
void CEditCommandGroup::Redo(){
|
|
for ( int i = 0; i < m_commands.Size(); i++ ) {
|
|
CEditCommand* item = m_commands[i];
|
|
item->Redo();
|
|
}
|
|
}
|
|
|
|
intn CEditCommandGroup::GetNumberOfCommands(){
|
|
return m_commands.Size();
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
void CEditCommandGroup::Print(IStreamOut& stream){
|
|
CEditCommand::Print(stream);
|
|
stream.Printf(" %d commands\n", m_commands.Size());
|
|
for ( int i = 0; i < m_commands.Size(); i++ ) {
|
|
CEditCommand* item = m_commands[i];
|
|
stream.Printf(" [%d] 0x%08x ", i, item);
|
|
item->Print(stream);
|
|
stream.Printf("\n");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// CSetListDataCommand
|
|
CSetListDataCommand::CSetListDataCommand(CEditBuffer* pBuffer, EDT_ListData& listData, intn id)
|
|
: CEditCommand(pBuffer, id)
|
|
{
|
|
m_newData = listData;
|
|
m_pOldData = NULL;
|
|
}
|
|
|
|
CSetListDataCommand::~CSetListDataCommand(){
|
|
if ( m_pOldData ){
|
|
CEditListElement::FreeData( m_pOldData );
|
|
}
|
|
}
|
|
|
|
void CSetListDataCommand::Do(){
|
|
m_pOldData = GetEditBuffer()->GetListData();
|
|
XP_ASSERT(m_pOldData);
|
|
GetEditBuffer()->SetListData(&m_newData);
|
|
}
|
|
|
|
void CSetListDataCommand::Undo(){
|
|
if ( m_pOldData ){
|
|
GetEditBuffer()->SetListData(m_pOldData);
|
|
}
|
|
}
|
|
|
|
void CSetListDataCommand::Redo(){
|
|
GetEditBuffer()->SetListData(&m_newData);
|
|
}
|
|
|
|
// CChangePageDataCommand
|
|
|
|
CChangePageDataCommand::CChangePageDataCommand(CEditBuffer* buffer, intn id)
|
|
: CEditCommand(buffer, id)
|
|
{
|
|
m_oldData = GetEditBuffer()->GetPageData();
|
|
m_newData = NULL;
|
|
}
|
|
|
|
CChangePageDataCommand::~CChangePageDataCommand(){
|
|
if ( m_oldData ) {
|
|
GetEditBuffer()->FreePageData(m_oldData);
|
|
}
|
|
if ( m_newData ) {
|
|
GetEditBuffer()->FreePageData(m_newData);
|
|
}
|
|
}
|
|
|
|
void CChangePageDataCommand::Undo(){
|
|
if ( ! m_newData ) {
|
|
m_newData = GetEditBuffer()->GetPageData();
|
|
}
|
|
GetEditBuffer()->SetPageData(m_oldData);
|
|
}
|
|
|
|
void CChangePageDataCommand::Redo(){
|
|
GetEditBuffer()->SetPageData(m_newData);
|
|
}
|
|
|
|
// CSetMetaDataCommand
|
|
|
|
CSetMetaDataCommand::CSetMetaDataCommand(CEditBuffer* buffer, EDT_MetaData *pMetaData, XP_Bool bDelete, intn id)
|
|
: CEditCommand(buffer, id){
|
|
m_bDelete = bDelete;
|
|
int existingIndex = GetEditBuffer()->FindMetaData( pMetaData);
|
|
m_bNewItem = existingIndex < 0;
|
|
if ( m_bNewItem ) {
|
|
m_pOldData = 0;
|
|
}
|
|
else {
|
|
m_pOldData = GetEditBuffer()->GetMetaData(existingIndex);
|
|
}
|
|
if ( m_bDelete ) {
|
|
GetEditBuffer()->DeleteMetaData(pMetaData);
|
|
m_pNewData = 0;
|
|
}
|
|
else {
|
|
GetEditBuffer()->SetMetaData(pMetaData);
|
|
m_pNewData = GetEditBuffer()->GetMetaData(GetEditBuffer()->FindMetaData(pMetaData));
|
|
}
|
|
}
|
|
|
|
CSetMetaDataCommand::~CSetMetaDataCommand(){
|
|
if ( m_pOldData ) {
|
|
GetEditBuffer()->FreeMetaData(m_pOldData);
|
|
}
|
|
if ( m_pNewData ) {
|
|
GetEditBuffer()->FreeMetaData(m_pNewData);
|
|
}
|
|
}
|
|
|
|
void CSetMetaDataCommand::Undo(){
|
|
if ( m_bNewItem ) {
|
|
if ( m_pNewData ) {
|
|
GetEditBuffer()->DeleteMetaData(m_pNewData);
|
|
}
|
|
}
|
|
else {
|
|
if ( m_pOldData ) {
|
|
GetEditBuffer()->SetMetaData(m_pOldData);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CSetMetaDataCommand::Redo(){
|
|
if ( m_bDelete ) {
|
|
if ( m_pOldData ) {
|
|
GetEditBuffer()->DeleteMetaData(m_pOldData);
|
|
}
|
|
}
|
|
else {
|
|
if ( m_pNewData ) {
|
|
GetEditBuffer()->SetMetaData(m_pNewData);
|
|
}
|
|
}
|
|
}
|
|
|
|
// CSetTableDataCommand
|
|
|
|
CSetTableDataCommand::CSetTableDataCommand(CEditBuffer* buffer, EDT_TableData* pTableData, intn id)
|
|
: CEditCommand(buffer, id){
|
|
m_pOldData = buffer->GetTableData();
|
|
GetEditBuffer()->SetTableData(pTableData);
|
|
m_pNewData = buffer->GetTableData();
|
|
}
|
|
|
|
CSetTableDataCommand::~CSetTableDataCommand(){
|
|
CEditTableElement::FreeData(m_pOldData);
|
|
CEditTableElement::FreeData(m_pNewData);
|
|
}
|
|
|
|
void CSetTableDataCommand::Undo(){
|
|
GetEditBuffer()->SetTableData(m_pOldData);
|
|
}
|
|
|
|
void CSetTableDataCommand::Redo(){
|
|
GetEditBuffer()->SetTableData(m_pNewData);
|
|
}
|
|
|
|
CSetTableCaptionDataCommand::CSetTableCaptionDataCommand(CEditBuffer* buffer, EDT_TableCaptionData* pTableData, intn id)
|
|
: CEditCommand(buffer, id){
|
|
m_pOldData = GetEditBuffer()->GetTableCaptionData();
|
|
GetEditBuffer()->SetTableCaptionData(pTableData);
|
|
m_pNewData = GetEditBuffer()->GetTableCaptionData();
|
|
}
|
|
|
|
CSetTableCaptionDataCommand::~CSetTableCaptionDataCommand(){
|
|
CEditCaptionElement::FreeData(m_pOldData);
|
|
CEditCaptionElement::FreeData(m_pNewData);
|
|
}
|
|
|
|
void CSetTableCaptionDataCommand::Undo(){
|
|
GetEditBuffer()->SetTableCaptionData(m_pOldData);
|
|
}
|
|
|
|
void CSetTableCaptionDataCommand::Redo(){
|
|
GetEditBuffer()->SetTableCaptionData(m_pNewData);
|
|
}
|
|
|
|
CSetTableRowDataCommand::CSetTableRowDataCommand(CEditBuffer* buffer, EDT_TableRowData* pTableData, intn id)
|
|
: CEditCommand(buffer, id){
|
|
m_pOldData = GetEditBuffer()->GetTableRowData();
|
|
GetEditBuffer()->SetTableRowData(pTableData);
|
|
m_pNewData = GetEditBuffer()->GetTableRowData();
|
|
}
|
|
|
|
CSetTableRowDataCommand::~CSetTableRowDataCommand(){
|
|
CEditTableRowElement::FreeData(m_pOldData);
|
|
CEditTableRowElement::FreeData(m_pNewData);
|
|
}
|
|
|
|
void CSetTableRowDataCommand::Undo(){
|
|
GetEditBuffer()->SetTableRowData(m_pOldData);
|
|
}
|
|
|
|
void CSetTableRowDataCommand::Redo(){
|
|
GetEditBuffer()->SetTableRowData(m_pNewData);
|
|
}
|
|
|
|
CSetTableCellDataCommand::CSetTableCellDataCommand(CEditBuffer* buffer, EDT_TableCellData* pTableData, intn id)
|
|
: CEditCommand(buffer, id){
|
|
m_pOldData = GetEditBuffer()->GetTableCellData();
|
|
GetEditBuffer()->SetTableCellData(pTableData);
|
|
m_pNewData = GetEditBuffer()->GetTableCellData();
|
|
}
|
|
|
|
CSetTableCellDataCommand::~CSetTableCellDataCommand(){
|
|
CEditTableCellElement::FreeData(m_pOldData);
|
|
CEditTableCellElement::FreeData(m_pNewData);
|
|
}
|
|
|
|
void CSetTableCellDataCommand::Undo(){
|
|
GetEditBuffer()->SetTableCellData(m_pOldData);
|
|
}
|
|
|
|
void CSetTableCellDataCommand::Redo(){
|
|
GetEditBuffer()->SetTableCellData(m_pNewData);
|
|
}
|
|
|
|
#ifdef SUPPORT_MULTICOLUMN
|
|
|
|
CSetMultiColumnDataCommand::CSetMultiColumnDataCommand(CEditBuffer* buffer, EDT_MultiColumnData* pMultiColumnData, intn id)
|
|
: CEditCommand(buffer, id){
|
|
m_pOldData = GetEditBuffer()->GetMultiColumnData();
|
|
GetEditBuffer()->SetMultiColumnData(pMultiColumnData);
|
|
m_pNewData = GetEditBuffer()->GetMultiColumnData();
|
|
}
|
|
|
|
CSetMultiColumnDataCommand::~CSetMultiColumnDataCommand(){
|
|
CEditMultiColumnElement::FreeData(m_pOldData);
|
|
CEditMultiColumnElement::FreeData(m_pNewData);
|
|
}
|
|
|
|
void CSetMultiColumnDataCommand::Undo(){
|
|
GetEditBuffer()->SetMultiColumnData(m_pOldData);
|
|
}
|
|
|
|
void CSetMultiColumnDataCommand::Redo(){
|
|
GetEditBuffer()->SetMultiColumnData(m_pNewData);
|
|
}
|
|
#endif
|
|
|
|
// CSetSelectionCommand
|
|
|
|
CSetSelectionCommand::CSetSelectionCommand(CEditBuffer* buffer, CEditSelection& selection, intn id)
|
|
: CEditCommand(buffer, id){
|
|
m_NewSelection = GetEditBuffer()->EphemeralToPersistent(selection);
|
|
}
|
|
|
|
CSetSelectionCommand::~CSetSelectionCommand(){
|
|
}
|
|
|
|
void CSetSelectionCommand::Do(){
|
|
GetEditBuffer()->GetSelection(m_OldSelection);
|
|
GetEditBuffer()->SetSelection(m_NewSelection);
|
|
}
|
|
|
|
void CSetSelectionCommand::Undo(){
|
|
GetEditBuffer()->SetSelection(m_OldSelection);
|
|
}
|
|
|
|
void CSetSelectionCommand::Redo(){
|
|
GetEditBuffer()->SetSelection(m_NewSelection);
|
|
}
|
|
|
|
#endif
|