Files
libreoffice/sc/source/ui/collab/sendfunc.cxx

403 lines
13 KiB
C++
Raw Normal View History

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* Version: MPL 1.1 / GPLv3+ / LGPLv3+
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License or as specified alternatively below. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* Major Contributor(s):
* Copyright (C) 2012 Michael Meeks <michael.meeks@suse.com> (initial developer)
*
* All Rights Reserved.
*
* For minor contributions see the git repository.
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 3 or later (the "GPLv3+"), or
* the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
* in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
* instead of those above.
*/
#include "sal/config.h"
#include <vector>
#include "cell.hxx"
#include "docsh.hxx"
#include "docfunc.hxx"
namespace {
rtl::OUString cellToString( ScBaseCell *pCell )
{
(void)pCell;
return rtl::OUString();
}
ScBaseCell *stringToCell( const rtl::OUString &rString )
{
(void)rString;
return NULL;
}
// Ye noddy mangling - needs improvement ...
// method name ';' then arguments ; separated
class ScChangeOpWriter
{
rtl::OUStringBuffer aMessage;
void appendSeparator()
{
aMessage.append( sal_Unicode( ';' ) );
}
public:
ScChangeOpWriter( const char *pName )
{
aMessage.appendAscii( pName );
appendSeparator();
}
void appendString( const String &rStr )
{
String aQuoted( rStr );
if ( ScGlobal::FindUnquoted( aQuoted, sal_Unicode( '"' ) ) != STRING_NOTFOUND )
ScGlobal::AddQuotes( aQuoted, sal_Unicode( '"' ) );
aMessage.append( aQuoted );
appendSeparator();
}
void appendString( const rtl::OUString &rStr )
{
aMessage.append( String( rStr ) );
}
void appendAddress( const ScAddress &rPos )
{
rtl::OUString aStr;
rPos.Format( aStr, SCA_VALID );
aMessage.append( aStr );
appendSeparator();
}
void appendInt( sal_Int32 i )
{
aMessage.append( i );
appendSeparator();
}
void appendBool( sal_Bool b )
{
aMessage.appendAscii( b ? "true" : "false" );
appendSeparator();
}
void appendCell( ScBaseCell *pCell )
{
appendString( cellToString( pCell ) );
}
rtl::OString toString()
{
return rtl::OUStringToOString( aMessage.toString(), RTL_TEXTENCODING_UTF8 );
}
};
struct ProtocolError {
const char *message;
};
class ScChangeOpReader {
std::vector< rtl::OUString > maArgs;
public:
ScChangeOpReader( const rtl::OUString &rString)
{
// will need to handle escaping etc.
// Surely someone else wrote this before ! [!?]
sal_Int32 n = 0, nStart = 0;
enum {
IN_TEXT, CHECK_QUOTE
} eState = IN_TEXT;
while (n < rString.getLength())
{
switch (eState) {
case CHECK_QUOTE:
if (rString[n] == '"')
{
xub_StrLen nLen = ScGlobal::FindUnquoted( rString, '"', n + 1 );
if (nLen == STRING_NOTFOUND)
{
fprintf( stderr, "Error: no closing '\"' \n" );
nLen = rString.getLength();
}
maArgs.push_back( rString.copy( n + 1, nLen - n - 1 ) );
n = nLen;
if ( nLen < rString.getLength() && rString[ nLen + 1 ] )
;
eState = IN_TEXT;
break;
} // drop through
case IN_TEXT:
if (rString[n] == ';')
{
maArgs.push_back( rString.copy( nStart, n ) );
n = nStart = n + 1;
eState = CHECK_QUOTE;
} else
n++;
break;
}
}
if ( nStart < rString.getLength())
maArgs.push_back( rString.copy( nStart, rString.getLength() - nStart ) );
for (size_t i = 0; i < maArgs.size(); i++)
fprintf( stderr, "arg %d: '%s'\n", (int)i,
rtl::OUStringToOString( maArgs[i], RTL_TEXTENCODING_UTF8).getStr() );
}
~ScChangeOpReader() {}
rtl::OUString getMethod()
{
return maArgs[0];
}
size_t getArgCount() { return maArgs.size(); }
rtl::OUString getString( sal_Int32 n )
{
if (n > 0 && (size_t)n < getArgCount() )
{
String aUStr( maArgs[ n ] );
ScGlobal::EraseQuotes( aUStr );
return aUStr;
} else
return rtl::OUString();
}
ScAddress getAddress( sal_Int32 n )
{
ScAddress aAddr;
rtl::OUString aToken( getString( n ) );
aAddr.Parse( aToken );
return aAddr;
}
sal_Int32 getInt( sal_Int32 n )
{
return getString( n ).toInt32();
}
bool getBool( sal_Int32 n )
{
return getString( n ).equalsIgnoreAsciiCase( "true" );
}
ScBaseCell *getCell( sal_Int32 n )
{
return stringToCell( getString( n ) );
}
};
class ScDocFuncRecv : public ScDocFunc
{
ScDocFunc *mpChain;
public:
// FIXME: really ScDocFunc should be an abstract base
ScDocFuncRecv( ScDocShell& rDocSh, ScDocFunc *pChain )
: ScDocFunc( rDocSh ),
mpChain( pChain )
{
fprintf( stderr, "Receiver created !\n" );
}
virtual ~ScDocFuncRecv() {}
void RecvMessage( const rtl::OString &rString )
{
try {
ScChangeOpReader aReader( rtl::OUString( rString.getStr(),
rString.getLength(),
RTL_TEXTENCODING_UTF8 ) );
// FIXME: have some hash to enumeration mapping here
if ( aReader.getMethod() == "setNormalString" )
mpChain->SetNormalString( aReader.getAddress( 1 ), aReader.getString( 2 ),
aReader.getBool( 3 ) );
else if ( aReader.getMethod() == "putCell" )
{
ScBaseCell *pNewCell = aReader.getCell( 2 );
if ( pNewCell )
mpChain->PutCell( aReader.getAddress( 1 ), pNewCell, aReader.getBool( 3 ) );
}
else if ( aReader.getMethod() == "enterListAction" )
mpChain->EnterListAction( aReader.getInt( 1 ) );
else if ( aReader.getMethod() == "endListAction" )
mpChain->EndListAction();
else if ( aReader.getMethod() == "showNote" )
mpChain->ShowNote( aReader.getAddress( 1 ), aReader.getBool( 2 ) );
else if ( aReader.getMethod() == "setNoteText" )
mpChain->SetNoteText( aReader.getAddress( 1 ), aReader.getString( 2 ),
aReader.getBool( 3 ) );
else if ( aReader.getMethod() == "renameTable" )
mpChain->RenameTable( aReader.getInt( 1 ), aReader.getString( 2 ),
aReader.getBool( 3 ), aReader.getBool( 4 ) );
else
fprintf( stderr, "Error: unknown message '%s' (%d)\n",
rString.getStr(), (int)aReader.getArgCount() );
} catch (const ProtocolError &e) {
fprintf( stderr, "Error: protocol twisting '%s'\n", e.message );
}
}
};
class ScDocFuncSend : public ScDocFunc
{
ScDocFuncRecv *mpChain;
void SendMessage( ScChangeOpWriter &rOp )
{
fprintf( stderr, "Op: '%s'\n", rOp.toString().getStr() );
mpChain->RecvMessage( rOp.toString() );
}
public:
// FIXME: really ScDocFunc should be an abstract base, so
// we don't need the rDocSh hack/pointer
ScDocFuncSend( ScDocShell& rDocSh, ScDocFuncRecv *pChain )
: ScDocFunc( rDocSh ),
mpChain( pChain )
{
fprintf( stderr, "Sender created !\n" );
}
virtual ~ScDocFuncSend() {}
virtual void EnterListAction( sal_uInt16 nNameResId )
{
// Want to group these operations for the other side ...
String aUndo( ScGlobal::GetRscString( nNameResId ) );
ScChangeOpWriter aOp( "enterListAction" );
aOp.appendInt( nNameResId ); // nasty but translate-able ...
SendMessage( aOp );
}
virtual void EndListAction()
{
ScChangeOpWriter aOp( "endListAction" );
SendMessage( aOp );
}
virtual sal_Bool SetNormalString( const ScAddress& rPos, const String& rText, sal_Bool bApi )
{
ScChangeOpWriter aOp( "setNormalString" );
aOp.appendAddress( rPos );
aOp.appendString( rText );
aOp.appendBool( bApi );
SendMessage( aOp );
return true; // needs some code auditing action
}
virtual sal_Bool PutCell( const ScAddress& rPos, ScBaseCell* pNewCell, sal_Bool bApi )
{
fprintf( stderr, "put cell '%p' type %d %d\n", pNewCell, pNewCell->GetCellType(), bApi );
ScChangeOpWriter aOp( "putCell" );
aOp.appendAddress( rPos );
aOp.appendCell( pNewCell );
aOp.appendBool( bApi );
SendMessage( aOp );
return true; // needs some code auditing action
}
virtual sal_Bool PutData( const ScAddress& rPos, ScEditEngineDefaulter& rEngine,
sal_Bool bInterpret, sal_Bool bApi )
{
fprintf( stderr, "put data\n" );
return mpChain->PutData( rPos, rEngine, bInterpret, bApi );
}
virtual sal_Bool SetCellText( const ScAddress& rPos, const String& rText,
sal_Bool bInterpret, sal_Bool bEnglish, sal_Bool bApi,
const String& rFormulaNmsp,
const formula::FormulaGrammar::Grammar eGrammar )
{
fprintf( stderr, "set cell text '%s'\n",
rtl::OUStringToOString( rText, RTL_TEXTENCODING_UTF8 ).getStr() );
return mpChain->SetCellText( rPos, rText, bInterpret, bEnglish, bApi, rFormulaNmsp, eGrammar );
}
virtual bool ShowNote( const ScAddress& rPos, bool bShow = true )
{
ScChangeOpWriter aOp( "showNote" );
aOp.appendAddress( rPos );
aOp.appendBool( bShow );
SendMessage( aOp );
return true; // needs some code auditing action
}
virtual bool SetNoteText( const ScAddress& rPos, const String& rNoteText, sal_Bool bApi )
{
ScChangeOpWriter aOp( "setNoteText" );
aOp.appendAddress( rPos );
aOp.appendString( rNoteText );
aOp.appendBool( bApi );
SendMessage( aOp );
return true; // needs some code auditing action
}
virtual sal_Bool RenameTable( SCTAB nTab, const String& rName,
sal_Bool bRecord, sal_Bool bApi )
{
ScChangeOpWriter aOp( "renameTable" );
aOp.appendInt( nTab );
aOp.appendString( rName );
aOp.appendBool( bRecord );
aOp.appendBool( bApi );
SendMessage( aOp );
return true; // needs some code auditing action
}
virtual sal_Bool ApplyAttributes( const ScMarkData& rMark, const ScPatternAttr& rPattern,
sal_Bool bRecord, sal_Bool bApi )
{
fprintf( stderr, "Apply Attributes\n" );
return mpChain->ApplyAttributes( rMark, rPattern, bRecord, bApi );
}
virtual sal_Bool ApplyStyle( const ScMarkData& rMark, const String& rStyleName,
sal_Bool bRecord, sal_Bool bApi )
{
fprintf( stderr, "Apply Style '%s'\n",
rtl::OUStringToOString( rStyleName, RTL_TEXTENCODING_UTF8 ).getStr() );
return mpChain->ApplyStyle( rMark, rStyleName, bRecord, bApi );
}
virtual sal_Bool MergeCells( const ScCellMergeOption& rOption, sal_Bool bContents,
sal_Bool bRecord, sal_Bool bApi )
{
fprintf( stderr, "Merge cells\n" );
return mpChain->MergeCells( rOption, bContents, bRecord, bApi );
}
};
} // anonymous namespace
SC_DLLPRIVATE ScDocFunc *ScDocShell::CreateDocFunc()
{
// FIXME: the chains should be auto-ptrs.
if (getenv ("INTERCEPT"))
return new ScDocFuncSend( *this, new ScDocFuncRecv( *this, new ScDocFuncDirect( *this ) ) );
else
return new ScDocFuncDirect( *this );
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */