From a3cc1cef516dd4e6b2992fe17968cdb68abeb849 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolnai=20Tam=C3=A1s?= Date: Sat, 4 Aug 2012 19:58:24 +0200 Subject: [PATCH] fdo#46193 MessBox was made copyable Part of MultiLineEdit was moved down from stvools to vcl with name VCLMultiLineEdit. MessBox uses it to display the message in read-only mode. Some of svtools' classes - which are necessary to implement VCLMultiLineEdit - were moved to vcl as a whole. Note: ExtTextView and ExtTextEngine classes would be leaved in svtools if VCLMultiLineEdit is a template class, but two macros: IMPL_LINK end IMPL_LINK_NOARG make it impossible to use template syntax. Change-Id: I6322983fc767bd90b0175c5e84004ee5b451b00b --- .../extended/textwindowaccessibility.hxx | 8 +- basctl/source/basicide/baside2.cxx | 2 +- basctl/source/basicide/baside2b.cxx | 4 +- basctl/source/basicide/basides1.cxx | 2 +- basctl/source/basicide/basides2.cxx | 6 +- basctl/source/basicide/linenumberwindow.cxx | 4 +- cui/source/dialogs/SpellAttrib.hxx | 2 +- cui/source/dialogs/SpellDialog.cxx | 2 +- cui/source/inc/SpellDialog.hxx | 2 +- desktop/source/deployment/gui/descedit.cxx | 4 +- .../deployment/gui/dp_gui_autoscrolledit.cxx | 2 +- desktop/source/deployment/gui/license_dialog.cxx | 2 +- editeng/inc/editeng/unoedhlp.hxx | 2 +- filter/source/xsltdialog/xmlfileview.cxx | 4 +- filter/source/xsltdialog/xmlfileview.hxx | 2 +- framework/source/services/license.cxx | 2 +- svtools/Library_svt.mk | 7 - svtools/Package_inc.mk | 5 - svtools/inc/svtools/svmedit.hxx | 110 +- svtools/inc/svtools/textdata.hxx | 172 -- svtools/inc/svtools/texteng.hxx | 332 -- svtools/inc/svtools/textview.hxx | 217 -- svtools/inc/svtools/txtattr.hxx | 236 -- svtools/inc/svtools/xtextedt.hxx | 69 - svtools/source/brwbox/ebbcontrols.cxx | 2 +- svtools/source/contnr/DocumentInfoPreview.cxx | 2 +- svtools/source/contnr/templwin.cxx | 4 +- svtools/source/edit/editsyntaxhighlighter.cxx | 4 +- svtools/source/edit/svmedit.cxx | 1573 +---------- svtools/source/edit/svmedit2.cxx | 2 +- svtools/source/edit/textdat2.hxx | 312 -- svtools/source/edit/textdata.cxx | 345 --- svtools/source/edit/textdoc.cxx | 636 ---- svtools/source/edit/textdoc.hxx | 145 - svtools/source/edit/texteng.cxx | 3205 -------------------- svtools/source/edit/textund2.hxx | 122 - svtools/source/edit/textundo.cxx | 295 -- svtools/source/edit/textundo.hxx | 85 - svtools/source/edit/textview.cxx | 2378 --------------- svtools/source/edit/textwindowpeer.cxx | 2 +- svtools/source/edit/txtattr.cxx | 164 - svtools/source/edit/xtextedt.cxx | 421 --- svx/source/dialog/docrecovery.cxx | 2 +- sw/source/ui/dbui/mmaddressblockpage.cxx | 4 +- sw/source/ui/docvw/srcedtw.cxx | 4 +- sw/source/ui/inc/srcedtw.hxx | 2 +- vcl/Library_vcl.mk | 9 + vcl/Package_inc.mk | 7 + vcl/inc/vcl/msgbox.hxx | 4 +- vcl/inc/vcl/textdata.hxx | 172 ++ vcl/inc/vcl/texteng.hxx | 332 ++ vcl/inc/vcl/textview.hxx | 217 ++ vcl/inc/vcl/txtattr.hxx | 236 ++ vcl/inc/vcl/vclmedit.hxx | 149 + vcl/inc/vcl/xtextedt.hxx | 69 + vcl/source/edit/textdat2.hxx | 312 ++ vcl/source/edit/textdata.cxx | 345 +++ vcl/source/edit/textdoc.cxx | 636 ++++ vcl/source/edit/textdoc.hxx | 145 + vcl/source/edit/texteng.cxx | 3205 ++++++++++++++++++++ vcl/source/edit/textund2.hxx | 122 + vcl/source/edit/textundo.cxx | 295 ++ vcl/source/edit/textundo.hxx | 85 + vcl/source/edit/textview.cxx | 2378 +++++++++++++++ vcl/source/edit/txtattr.cxx | 164 + vcl/source/edit/vclmedit.cxx | 1572 ++++++++++ vcl/source/edit/xtextedt.cxx | 421 +++ vcl/source/window/msgbox.cxx | 41 +- 68 files changed, 10947 insertions(+), 10876 deletions(-) delete mode 100644 svtools/inc/svtools/textdata.hxx delete mode 100644 svtools/inc/svtools/texteng.hxx delete mode 100644 svtools/inc/svtools/textview.hxx delete mode 100644 svtools/inc/svtools/txtattr.hxx delete mode 100644 svtools/inc/svtools/xtextedt.hxx delete mode 100644 svtools/source/edit/textdat2.hxx delete mode 100644 svtools/source/edit/textdata.cxx delete mode 100644 svtools/source/edit/textdoc.cxx delete mode 100644 svtools/source/edit/textdoc.hxx delete mode 100644 svtools/source/edit/texteng.cxx delete mode 100644 svtools/source/edit/textund2.hxx delete mode 100644 svtools/source/edit/textundo.cxx delete mode 100644 svtools/source/edit/textundo.hxx delete mode 100644 svtools/source/edit/textview.cxx delete mode 100644 svtools/source/edit/txtattr.cxx delete mode 100644 svtools/source/edit/xtextedt.cxx create mode 100644 vcl/inc/vcl/textdata.hxx create mode 100644 vcl/inc/vcl/texteng.hxx create mode 100644 vcl/inc/vcl/textview.hxx create mode 100644 vcl/inc/vcl/txtattr.hxx create mode 100644 vcl/inc/vcl/vclmedit.hxx create mode 100644 vcl/inc/vcl/xtextedt.hxx create mode 100644 vcl/source/edit/textdat2.hxx create mode 100644 vcl/source/edit/textdata.cxx create mode 100644 vcl/source/edit/textdoc.cxx create mode 100644 vcl/source/edit/textdoc.hxx create mode 100644 vcl/source/edit/texteng.cxx create mode 100644 vcl/source/edit/textund2.hxx create mode 100644 vcl/source/edit/textundo.cxx create mode 100644 vcl/source/edit/textundo.hxx create mode 100644 vcl/source/edit/textview.cxx create mode 100644 vcl/source/edit/txtattr.cxx create mode 100644 vcl/source/edit/vclmedit.cxx create mode 100644 vcl/source/edit/xtextedt.cxx diff --git a/accessibility/inc/accessibility/extended/textwindowaccessibility.hxx b/accessibility/inc/accessibility/extended/textwindowaccessibility.hxx index f1557e1..1ee7a3b 100644 --- a/accessibility/inc/accessibility/extended/textwindowaccessibility.hxx +++ b/accessibility/inc/accessibility/extended/textwindowaccessibility.hxx @@ -31,10 +31,10 @@ #include #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/basctl/source/basicide/baside2.cxx b/basctl/source/basicide/baside2.cxx index 1eab598..2a91daa 100644 --- a/basctl/source/basicide/baside2.cxx +++ b/basctl/source/basicide/baside2.cxx @@ -42,7 +42,7 @@ #include #include #include -#include +#include #include #include diff --git a/basctl/source/basicide/baside2b.cxx b/basctl/source/basicide/baside2b.cxx index a5702c1..95c887d 100644 --- a/basctl/source/basicide/baside2b.cxx +++ b/basctl/source/basicide/baside2b.cxx @@ -38,8 +38,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include diff --git a/basctl/source/basicide/basides1.cxx b/basctl/source/basicide/basides1.cxx index f4eb16d..435f28d 100644 --- a/basctl/source/basicide/basides1.cxx +++ b/basctl/source/basicide/basides1.cxx @@ -51,7 +51,7 @@ #include #include #include -#include +#include #include using namespace ::com::sun::star; diff --git a/basctl/source/basicide/basides2.cxx b/basctl/source/basicide/basides2.cxx index 4de4d77..cff69a3 100644 --- a/basctl/source/basicide/basides2.cxx +++ b/basctl/source/basicide/basides2.cxx @@ -29,9 +29,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/basctl/source/basicide/linenumberwindow.cxx b/basctl/source/basicide/linenumberwindow.cxx index 97674a6..b6d5223 100644 --- a/basctl/source/basicide/linenumberwindow.cxx +++ b/basctl/source/basicide/linenumberwindow.cxx @@ -29,8 +29,8 @@ #include "baside2.hxx" #include "linenumberwindow.hxx" -#include -#include +#include +#include LineNumberWindow::LineNumberWindow( Window* pParent, ModulWindow* pModulWin ) : Window( pParent, WB_BORDER ), diff --git a/cui/source/dialogs/SpellAttrib.hxx b/cui/source/dialogs/SpellAttrib.hxx index 4a260f5..1cc0304 100644 --- a/cui/source/dialogs/SpellAttrib.hxx +++ b/cui/source/dialogs/SpellAttrib.hxx @@ -28,7 +28,7 @@ #ifndef _SVX_SPELL_ATTRIB #define _SVX_SPELL_ATTRIB -#include +#include #include #include #include diff --git a/cui/source/dialogs/SpellDialog.cxx b/cui/source/dialogs/SpellDialog.cxx index c832bbc..9dcd2ac 100644 --- a/cui/source/dialogs/SpellDialog.cxx +++ b/cui/source/dialogs/SpellDialog.cxx @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/cui/source/inc/SpellDialog.hxx b/cui/source/inc/SpellDialog.hxx index c9cac11..c58ff7b 100644 --- a/cui/source/inc/SpellDialog.hxx +++ b/cui/source/inc/SpellDialog.hxx @@ -48,7 +48,7 @@ #include #include #include -#include +#include #include #include diff --git a/desktop/source/deployment/gui/descedit.cxx b/desktop/source/deployment/gui/descedit.cxx index b90061e..49ab5b6 100644 --- a/desktop/source/deployment/gui/descedit.cxx +++ b/desktop/source/deployment/gui/descedit.cxx @@ -19,8 +19,8 @@ #include -#include -#include +#include +#include #include "descedit.hxx" diff --git a/desktop/source/deployment/gui/dp_gui_autoscrolledit.cxx b/desktop/source/deployment/gui/dp_gui_autoscrolledit.cxx index cf3c740..d3a76d9 100644 --- a/desktop/source/deployment/gui/dp_gui_autoscrolledit.cxx +++ b/desktop/source/deployment/gui/dp_gui_autoscrolledit.cxx @@ -19,7 +19,7 @@ #include "svtools/svmedit2.hxx" #include "svl/lstner.hxx" -#include "svtools/xtextedt.hxx" +#include "vcl/xtextedt.hxx" #include "vcl/scrbar.hxx" #include "dp_gui_autoscrolledit.hxx" diff --git a/desktop/source/deployment/gui/license_dialog.cxx b/desktop/source/deployment/gui/license_dialog.cxx index 2a76bba..3e1e23e 100644 --- a/desktop/source/deployment/gui/license_dialog.cxx +++ b/desktop/source/deployment/gui/license_dialog.cxx @@ -40,7 +40,7 @@ #include "com/sun/star/task/XJobExecutor.hpp" #include "svtools/svmedit.hxx" #include "svl/lstner.hxx" -#include "svtools/xtextedt.hxx" +#include "vcl/xtextedt.hxx" #include #include "vcl/threadex.hxx" diff --git a/editeng/inc/editeng/unoedhlp.hxx b/editeng/inc/editeng/unoedhlp.hxx index df625f5..5848338 100644 --- a/editeng/inc/editeng/unoedhlp.hxx +++ b/editeng/inc/editeng/unoedhlp.hxx @@ -31,7 +31,7 @@ #include #include -#include +#include #include #include #include "editeng/editengdllapi.h" diff --git a/filter/source/xsltdialog/xmlfileview.cxx b/filter/source/xsltdialog/xmlfileview.cxx index ca1fa3f..a200a92 100644 --- a/filter/source/xsltdialog/xmlfileview.cxx +++ b/filter/source/xsltdialog/xmlfileview.cxx @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include #include @@ -44,7 +44,7 @@ #include #include #include -#include +#include #include "xmlfilterdialogstrings.hrc" #include "xmlfiltersettingsdialog.hxx" diff --git a/filter/source/xsltdialog/xmlfileview.hxx b/filter/source/xsltdialog/xmlfileview.hxx index abbe487..51684f1 100644 --- a/filter/source/xsltdialog/xmlfileview.hxx +++ b/filter/source/xsltdialog/xmlfileview.hxx @@ -32,7 +32,7 @@ #include #include -#include +#include #include #include #include diff --git a/framework/source/services/license.cxx b/framework/source/services/license.cxx index c91321b..99753a7b 100644 --- a/framework/source/services/license.cxx +++ b/framework/source/services/license.cxx @@ -62,7 +62,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/svtools/Library_svt.mk b/svtools/Library_svt.mk index c5f3e83..433ac78 100644 --- a/svtools/Library_svt.mk +++ b/svtools/Library_svt.mk @@ -146,14 +146,7 @@ $(eval $(call gb_Library_add_exception_objects,svt,\ svtools/source/edit/svmedit \ svtools/source/edit/svmedit2 \ svtools/source/edit/syntaxhighlight \ - svtools/source/edit/textdata \ - svtools/source/edit/textdoc \ - svtools/source/edit/texteng \ - svtools/source/edit/textundo \ - svtools/source/edit/textview \ svtools/source/edit/textwindowpeer \ - svtools/source/edit/txtattr \ - svtools/source/edit/xtextedt \ svtools/source/filter/FilterConfigCache \ svtools/source/filter/FilterConfigItem \ svtools/source/filter/SvFilterOptionsDialog \ diff --git a/svtools/Package_inc.mk b/svtools/Package_inc.mk index a7ce3a1..21953b1 100644 --- a/svtools/Package_inc.mk +++ b/svtools/Package_inc.mk @@ -155,9 +155,6 @@ $(eval $(call gb_Package_add_file,svtools_inc,inc/svtools/table/tabletypes.hxx,s $(eval $(call gb_Package_add_file,svtools_inc,inc/svtools/table/tablesort.hxx,svtools/table/tablesort.hxx)) $(eval $(call gb_Package_add_file,svtools_inc,inc/svtools/templatefoldercache.hxx,svtools/templatefoldercache.hxx)) $(eval $(call gb_Package_add_file,svtools_inc,inc/svtools/templdlg.hxx,svtools/templdlg.hxx)) -$(eval $(call gb_Package_add_file,svtools_inc,inc/svtools/textdata.hxx,svtools/textdata.hxx)) -$(eval $(call gb_Package_add_file,svtools_inc,inc/svtools/texteng.hxx,svtools/texteng.hxx)) -$(eval $(call gb_Package_add_file,svtools_inc,inc/svtools/textview.hxx,svtools/textview.hxx)) $(eval $(call gb_Package_add_file,svtools_inc,inc/svtools/textwindowpeer.hxx,svtools/textwindowpeer.hxx)) $(eval $(call gb_Package_add_file,svtools_inc,inc/svtools/toolbarmenu.hxx,svtools/toolbarmenu.hxx)) $(eval $(call gb_Package_add_file,svtools_inc,inc/svtools/toolboxcontroller.hxx,svtools/toolboxcontroller.hxx)) @@ -172,7 +169,6 @@ $(eval $(call gb_Package_add_file,svtools_inc,inc/svtools/toolpanel/toolpanel.hx $(eval $(call gb_Package_add_file,svtools_inc,inc/svtools/toolpanel/toolpaneldeck.hxx,svtools/toolpanel/toolpaneldeck.hxx)) $(eval $(call gb_Package_add_file,svtools_inc,inc/svtools/transfer.hxx,svtools/transfer.hxx)) $(eval $(call gb_Package_add_file,svtools_inc,inc/svtools/treelist.hxx,svtools/treelist.hxx)) -$(eval $(call gb_Package_add_file,svtools_inc,inc/svtools/txtattr.hxx,svtools/txtattr.hxx)) $(eval $(call gb_Package_add_file,svtools_inc,inc/svtools/txtcmp.hxx,svtools/txtcmp.hxx)) $(eval $(call gb_Package_add_file,svtools_inc,inc/svtools/unitconv.hxx,svtools/unitconv.hxx)) $(eval $(call gb_Package_add_file,svtools_inc,inc/svtools/unoevent.hxx,svtools/unoevent.hxx)) @@ -183,7 +179,6 @@ $(eval $(call gb_Package_add_file,svtools_inc,inc/svtools/wallitem.hxx,svtools/w $(eval $(call gb_Package_add_file,svtools_inc,inc/svtools/wizardmachine.hxx,svtools/wizardmachine.hxx)) $(eval $(call gb_Package_add_file,svtools_inc,inc/svtools/wizdlg.hxx,svtools/wizdlg.hxx)) $(eval $(call gb_Package_add_file,svtools_inc,inc/svtools/wmf.hxx,svtools/wmf.hxx)) -$(eval $(call gb_Package_add_file,svtools_inc,inc/svtools/xtextedt.hxx,svtools/xtextedt.hxx)) $(eval $(call gb_Package_add_file,svtools_inc,inc/svtools/xwindowitem.hxx,svtools/xwindowitem.hxx)) # vim: set noet sw=4 ts=4: diff --git a/svtools/inc/svtools/svmedit.hxx b/svtools/inc/svtools/svmedit.hxx index f0d30d1..9085349 100644 --- a/svtools/inc/svtools/svmedit.hxx +++ b/svtools/inc/svtools/svmedit.hxx @@ -29,127 +29,27 @@ #ifndef _SVEDIT_HXX #define _SVEDIT_HXX -#include -#include +#include #include #include #include -class ImpSvMEdit; -class Timer; -class ExtTextEngine; -class ExtTextView; -class SVT_DLLPUBLIC MultiLineEdit : public Edit -{ -private: - ImpSvMEdit* pImpSvMEdit; - - XubString aSaveValue; - Link aModifyHdlLink; - - Timer* pUpdateDataTimer; - Link aUpdateDataHdlLink; - -protected: - - DECL_LINK( ImpUpdateDataHdl, void* ); - void StateChanged( StateChangedType nType ); - void DataChanged( const DataChangedEvent& rDCEvt ); - virtual long PreNotify( NotifyEvent& rNEvt ); - long Notify( NotifyEvent& rNEvt ); - using Control::ImplInitSettings; - void ImplInitSettings( sal_Bool bFont, sal_Bool bForeground, sal_Bool bBackground ); - WinBits ImplInitStyle( WinBits nStyle ); - - ExtTextEngine* GetTextEngine() const; - ExtTextView* GetTextView() const; - ScrollBar* GetVScrollBar() const; +class SVT_DLLPUBLIC MultiLineEdit : public VCLMultiLineEdit +{ public: MultiLineEdit( Window* pParent, WinBits nWinStyle = WB_LEFT | WB_BORDER ); MultiLineEdit( Window* pParent, const ResId& rResId ); - ~MultiLineEdit(); - - - virtual void Modify(); - virtual void UpdateData(); - - virtual void SetModifyFlag(); - virtual void ClearModifyFlag(); - virtual sal_Bool IsModified() const; - - virtual void EnableUpdateData( sal_uLong nTimeout = EDIT_UPDATEDATA_TIMEOUT ); - virtual void DisableUpdateData() { delete pUpdateDataTimer; pUpdateDataTimer = NULL; } - virtual sal_uLong IsUpdateDataEnabled() const; - - virtual void SetReadOnly( sal_Bool bReadOnly = sal_True ); - virtual sal_Bool IsReadOnly() const; - - void EnableFocusSelectionHide( sal_Bool bHide ); - - virtual void SetMaxTextLen( xub_StrLen nMaxLen = 0 ); - virtual xub_StrLen GetMaxTextLen() const; - - virtual void SetSelection( const Selection& rSelection ); - virtual const Selection& GetSelection() const; - - virtual void ReplaceSelected( const XubString& rStr ); - virtual void DeleteSelected(); - virtual XubString GetSelected() const; - virtual XubString GetSelected( LineEnd aSeparator ) const; - - virtual void Cut(); - virtual void Copy(); - virtual void Paste(); - - virtual void SetText( const XubString& rStr ); - virtual void SetText( const XubString& rStr, const Selection& rNewSelection ) - { SetText( rStr ); SetSelection( rNewSelection ); } - String GetText() const; - String GetText( LineEnd aSeparator ) const; - String GetTextLines( LineEnd aSeparator ) const; - - void SetRightToLeft( sal_Bool bRightToLeft ); - sal_Bool IsRightToLeft() const; - - void SaveValue() { aSaveValue = GetText(); } - const XubString& GetSavedValue() const { return aSaveValue; } - - void SetModifyHdl( const Link& rLink ) { aModifyHdlLink = rLink; } - const Link& GetModifyHdl() const { return aModifyHdlLink; } - - void SetUpdateDataHdl( const Link& rLink ) { aUpdateDataHdlLink = rLink; } - const Link& GetUpdateDataHdl() const { return aUpdateDataHdlLink; } - - virtual void Resize(); - virtual void GetFocus(); - - Size CalcMinimumSize() const; - Size CalcAdjustedSize( const Size& rPrefSize ) const; - using Edit::CalcSize; - Size CalcSize( sal_uInt16 nColumns, sal_uInt16 nLines ) const; - void GetMaxVisColumnsAndLines( sal_uInt16& rnCols, sal_uInt16& rnLines ) const; - - void Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, sal_uLong nFlags ); - - void SetLeftMargin( sal_uInt16 n ); + ~MultiLineEdit(){}; virtual ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindowPeer > GetComponentInterface(sal_Bool bCreate = sal_True); - - void DisableSelectionOnFocus(); - - void SetTextSelectable( sal_Bool bTextSelectable ); }; -inline sal_uLong MultiLineEdit::IsUpdateDataEnabled() const -{ - return pUpdateDataTimer ? pUpdateDataTimer->GetTimeout() : 0; -} -#endif +#endif //_SVEDIT_HXX /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svtools/inc/svtools/textdata.hxx b/svtools/inc/svtools/textdata.hxx deleted file mode 100644 index 29d97e6..0000000 --- a/svtools/inc/svtools/textdata.hxx +++ /dev/null @@ -1,172 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#ifndef _TEXTDATA_HXX -#define _TEXTDATA_HXX - -#include "svtools/svtdllapi.h" -#include -#include -#include - -// Fuer Notify, wenn alle Absaetze geloescht wurden... -#define TEXT_PARA_ALL 0xFFFFFFFF - -class TextPaM -{ -private: - sal_uLong mnPara; - sal_uInt16 mnIndex; - -public: - TextPaM() { mnPara = 0, mnIndex = 0; } - TextPaM( sal_uLong nPara, sal_uInt16 nIndex ) { mnPara = nPara, mnIndex = nIndex; } - - sal_uLong GetPara() const { return mnPara; } - sal_uLong& GetPara() { return mnPara; } - - sal_uInt16 GetIndex() const { return mnIndex; } - sal_uInt16& GetIndex() { return mnIndex; } - - inline sal_Bool operator == ( const TextPaM& rPaM ) const; - inline sal_Bool operator != ( const TextPaM& rPaM ) const; - inline sal_Bool operator < ( const TextPaM& rPaM ) const; - inline sal_Bool operator > ( const TextPaM& rPaM ) const; -}; - -inline sal_Bool TextPaM::operator == ( const TextPaM& rPaM ) const -{ - return ( ( mnPara == rPaM.mnPara ) && ( mnIndex == rPaM.mnIndex ) ) ? sal_True : sal_False; -} - -inline sal_Bool TextPaM::operator != ( const TextPaM& rPaM ) const -{ - return !( *this == rPaM ); -} - -inline sal_Bool TextPaM::operator < ( const TextPaM& rPaM ) const -{ - return ( ( mnPara < rPaM.mnPara ) || - ( ( mnPara == rPaM.mnPara ) && mnIndex < rPaM.mnIndex ) ) ? sal_True : sal_False; -} - -inline sal_Bool TextPaM::operator > ( const TextPaM& rPaM ) const -{ - return ( ( mnPara > rPaM.mnPara ) || - ( ( mnPara == rPaM.mnPara ) && mnIndex > rPaM.mnIndex ) ) ? sal_True : sal_False; -} - -class SVT_DLLPUBLIC TextSelection -{ -private: - TextPaM maStartPaM; - TextPaM maEndPaM; - -public: - TextSelection(); - TextSelection( const TextPaM& rPaM ); - TextSelection( const TextPaM& rStart, const TextPaM& rEnd ); - - const TextPaM& GetStart() const { return maStartPaM; } - TextPaM& GetStart() { return maStartPaM; } - - const TextPaM& GetEnd() const { return maEndPaM; } - TextPaM& GetEnd() { return maEndPaM; } - - void Justify(); - - sal_Bool HasRange() const { return maStartPaM != maEndPaM; } - - inline sal_Bool operator == ( const TextSelection& rSel ) const; - inline sal_Bool operator != ( const TextSelection& rSel ) const; -}; - -inline sal_Bool TextSelection::operator == ( const TextSelection& rSel ) const -{ - return ( ( maStartPaM == rSel.maStartPaM ) && ( maEndPaM == rSel.maEndPaM ) ); -} - -inline sal_Bool TextSelection::operator != ( const TextSelection& rSel ) const -{ - return !( *this == rSel ); -} - -#define TEXT_HINT_PARAINSERTED 1 -#define TEXT_HINT_PARAREMOVED 2 -#define TEXT_HINT_PARACONTENTCHANGED 3 -#define TEXT_HINT_TEXTHEIGHTCHANGED 4 -#define TEXT_HINT_FORMATPARA 5 -#define TEXT_HINT_TEXTFORMATTED 6 -#define TEXT_HINT_MODIFIED 7 -#define TEXT_HINT_BLOCKNOTIFICATION_START 8 -#define TEXT_HINT_BLOCKNOTIFICATION_END 9 -#define TEXT_HINT_INPUT_START 10 -#define TEXT_HINT_INPUT_END 11 - -#define TEXT_HINT_VIEWSCROLLED 100 -#define TEXT_HINT_VIEWSELECTIONCHANGED 101 - -class SVT_DLLPUBLIC TextHint : public SfxSimpleHint -{ -private: - sal_uLong mnValue; - -public: - TYPEINFO(); - TextHint( sal_uLong nId ); - TextHint( sal_uLong nId, sal_uLong nValue ); - - sal_uLong GetValue() const { return mnValue; } - void SetValue( sal_uLong n ) { mnValue = n; } -}; - -struct TEIMEInfos -{ - String aOldTextAfterStartPos; - sal_uInt16* pAttribs; - TextPaM aPos; - sal_uInt16 nLen; - sal_Bool bCursor; - sal_Bool bWasCursorOverwrite; - - TEIMEInfos( const TextPaM& rPos, const String& rOldTextAfterStartPos ); - ~TEIMEInfos(); - - void CopyAttribs( const sal_uInt16* pA, sal_uInt16 nL ); - void DestroyAttribs(); -}; - -// ----------------- Wrapper for old Tools List ------------------- - -#include -#include - -template class ToolsList : public ::std::vector< T > -{ -public: - sal_uLong Count() const { return static_cast(::std::vector< T >::size()); } - sal_uLong GetPos( T pObject ) const { return ( ::std::find( this->begin(), this->end(), pObject ) ) - this->begin(); } - T GetObject( sal_uLong nIndex ) const { return (*this)[nIndex]; } - void Insert( T pObject, sal_uLong nPos ) { ::std::vector< T >::insert( this->begin()+nPos, pObject ); } - void Remove( sal_uLong nPos ) { ::std::vector< T >::erase( this->begin()+nPos ); } -}; - -#endif // _TEXTDATA_HXX - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svtools/inc/svtools/texteng.hxx b/svtools/inc/svtools/texteng.hxx deleted file mode 100644 index b20a01b..0000000 --- a/svtools/inc/svtools/texteng.hxx +++ /dev/null @@ -1,332 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2000, 2010 Oracle and/or its affiliates. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * - * for a copy of the LGPLv3 License. - * - ************************************************************************/ -#ifndef _TEXTENG_HXX -#define _TEXTENG_HXX - -#include "svtools/svtdllapi.h" - -class TextDoc; -class TextView; -class TextPaM; -class TextSelection; -class TEParaPortions; -class TextAttrib; -class TextCharAttrib; -class TextUndo; -class TextUndoManager; -class EditSelFunctionSet; -class EditSelEngine; -class IdleFormatter; -class TextNode; -class OutputDevice; -class SfxUndoAction; -class KeyEvent; -class Timer; - -namespace svl -{ - class IUndoManager; -} - -class TextLine; -class TETextPortion; -#include -#include -#include -#include -#include - -#include -#include - -struct TEIMEInfos; -class SvtCTLOptions; - -namespace com { -namespace sun { -namespace star { -namespace i18n { - class XBreakIterator; - class XExtendedInputSequenceChecker; -}}}} - -class LocaleDataWrapper; - -enum TxtAlign { TXTALIGN_LEFT, TXTALIGN_CENTER, TXTALIGN_RIGHT }; - -typedef std::vector TextViews; - -class SVT_DLLPUBLIC TextEngine : public SfxBroadcaster -{ - friend class TextView; - friend class TextSelFunctionSet; - friend class ExtTextEngine; - friend class ExtTextView; - - friend class TextUndo; - friend class TextUndoManager; - friend class TextUndoDelPara; - friend class TextUndoConnectParas; - friend class TextUndoSplitPara; - friend class TextUndoInsertChars; - friend class TextUndoRemoveChars; - friend class TextUndoSetAttribs; - -private: - TextDoc* mpDoc; - TEParaPortions* mpTEParaPortions; - OutputDevice* mpRefDev; - - TextViews* mpViews; - TextView* mpActiveView; - - TextUndoManager* mpUndoManager; - - IdleFormatter* mpIdleFormatter; - - TEIMEInfos* mpIMEInfos; - - ::com::sun::star::lang::Locale maLocale; - ::com::sun::star::uno::Reference< ::com::sun::star::i18n::XBreakIterator > mxBreakIterator; - - Rectangle maInvalidRec; - Range maInvalidRange; - - LocaleDataWrapper* mpLocaleDataWrapper; - - Font maFont; - Color maTextColor; - sal_uInt16 mnCharHeight; - sal_uInt16 mnFixCharWidth100; - - sal_uLong mnMaxTextLen; - sal_uLong mnMaxTextWidth; - sal_uLong mnCurTextWidth; - sal_uLong mnCurTextHeight; - sal_uLong mnDefTab; - - TxtAlign meAlign; - - sal_Bool mbIsFormatting : 1; // Semaphore wegen der Hook's - sal_Bool mbFormatted : 1; - sal_Bool mbUpdate : 1; - sal_Bool mbModified : 1; - sal_Bool mbUndoEnabled : 1; - sal_Bool mbIsInUndo : 1; - sal_Bool mbDowning : 1; - sal_Bool mbRightToLeft : 1; - sal_Bool mbHasMultiLineParas : 1; - - TextEngine( const TextEngine& ) : SfxBroadcaster() {} - TextEngine& operator=( const TextEngine& ) { return *this; } - -protected: - - void CursorMoved( sal_uLong nNode ); - void TextModified(); - - void ImpInitDoc(); - void ImpRemoveText(); - TextPaM ImpDeleteText( const TextSelection& rSel ); - TextPaM ImpInsertText( const TextSelection& rSel, sal_Unicode c, sal_Bool bOverwrite = sal_False ); - TextPaM ImpInsertText( const TextSelection& rSel, const String& rText ); - TextPaM ImpInsertParaBreak( const TextSelection& rTextSelection, sal_Bool bKeepEndingAttribs = sal_True ); - TextPaM ImpInsertParaBreak( const TextPaM& rPaM, sal_Bool bKeepEndingAttribs = sal_True ); - void ImpRemoveChars( const TextPaM& rPaM, sal_uInt16 nChars, SfxUndoAction* pCurUndo = 0 ); - TextPaM ImpConnectParagraphs( sal_uLong nLeft, sal_uLong nRight ); - void ImpRemoveParagraph( sal_uLong nPara ); - void ImpInitWritingDirections( sal_uLong nPara ); - LocaleDataWrapper* ImpGetLocaleDataWrapper(); - - // to remain compatible in the minor release we copy the above ImpInsertText - // function and add the extra parameter we need but make sure this function - // gets not exported. First and seconf parameter swapped to have a different signatur. - SAL_DLLPRIVATE TextPaM ImpInsertText( sal_Unicode c, const TextSelection& rSel, sal_Bool bOverwrite = sal_False, sal_Bool bIsUserInput = sal_False ); - // some other new functions needed that must not be exported to remain compatible - SAL_DLLPRIVATE ::com::sun::star::uno::Reference < ::com::sun::star::i18n::XExtendedInputSequenceChecker > GetInputSequenceChecker() const; - SAL_DLLPRIVATE sal_Bool IsInputSequenceCheckingRequired( sal_Unicode c, const TextSelection& rCurSel ) const; - - // Broadcasten bzw. Selektionen anpassen: - void ImpParagraphInserted( sal_uLong nPara ); - void ImpParagraphRemoved( sal_uLong nPara ); - void ImpCharsRemoved( sal_uLong nPara, sal_uInt16 nPos, sal_uInt16 nChars ); - void ImpCharsInserted( sal_uLong nPara, sal_uInt16 nPos, sal_uInt16 nChars ); - void ImpFormattingParagraph( sal_uLong nPara ); - void ImpTextHeightChanged(); - void ImpTextFormatted(); - - DECL_LINK( IdleFormatHdl, void * ); - void CheckIdleFormatter(); - void IdleFormatAndUpdate( TextView* pCurView = 0, sal_uInt16 nMaxTimerRestarts = 5 ); - - sal_Bool CreateLines( sal_uLong nPara ); - void CreateAndInsertEmptyLine( sal_uLong nPara ); - void ImpBreakLine( sal_uLong nPara, TextLine* pLine, TETextPortion* pPortion, sal_uInt16 nPortionStart, long nRemainingWidth ); - sal_uInt16 SplitTextPortion( sal_uLong nPara, sal_uInt16 nPos ); - void CreateTextPortions( sal_uLong nPara, sal_uInt16 nStartPos ); - void RecalcTextPortion( sal_uLong nPara, sal_uInt16 nStartPos, short nNewChars ); - void SeekCursor( sal_uLong nNode, sal_uInt16 nPos, Font& rFont, OutputDevice* pOutDev ); - - void FormatDoc(); - void FormatFullDoc(); - void FormatAndUpdate( TextView* pCurView = 0 ); - sal_Bool IsFormatting() const { return mbIsFormatting; } - void UpdateViews( TextView* pCurView = 0 ); - - void ImpPaint( OutputDevice* pOut, const Point& rStartPos, Rectangle const* pPaintArea, TextSelection const* pPaintRange = 0, TextSelection const* pSelection = 0 ); - - void UpdateSelections(); - - sal_Bool IsFormatted() const { return mbFormatted; } - - sal_uInt16 GetCharPos( sal_uLong nPara, sal_uInt16 nLine, long nDocPosX, sal_Bool bSmart = sal_False ); - Rectangle GetEditCursor( const TextPaM& rPaM, sal_Bool bSpecial, sal_Bool bPreferPortionStart = sal_False ); - sal_uInt16 ImpFindIndex( sal_uLong nPortion, const Point& rPosInPara, sal_Bool bSmart ); - long ImpGetPortionXOffset( sal_uLong nPara, TextLine* pLine, sal_uInt16 nTextPortion ); - long ImpGetXPos( sal_uLong nPara, TextLine* pLine, sal_uInt16 nIndex, sal_Bool bPreferPortionStart = sal_False ); - long ImpGetOutputOffset( sal_uLong nPara, TextLine* pLine, sal_uInt16 nIndex, sal_uInt16 nIndex2 ); - sal_uInt8 ImpGetRightToLeft( sal_uLong nPara, sal_uInt16 nPos, sal_uInt16* pStart = NULL, sal_uInt16* pEnd = NULL ); - void ImpInitLayoutMode( OutputDevice* pOutDev, sal_Bool bDrawingR2LPortion = sal_False ); - TxtAlign ImpGetAlign() const; - - sal_uLong CalcTextHeight(); - sal_uLong CalcParaHeight( sal_uLong nParagraph ) const; - sal_uLong CalcTextWidth( sal_uLong nPara ); - sal_uLong CalcTextWidth( sal_uLong nPara, sal_uInt16 nPortionStart, sal_uInt16 nPortionLen, const Font* pFont = 0 ); - Range GetInvalidYOffsets( sal_uLong nPortion ); - - // Fuer Undo/Redo - void InsertContent( TextNode* pNode, sal_uLong nPara ); - TextPaM SplitContent( sal_uLong nNode, sal_uInt16 nSepPos ); - TextPaM ConnectContents( sal_uLong nLeftNode ); - - // Ans API uebergebene PaM's und Selektionen auf einen gueltigen Bereich einstellen - void ValidateSelection( TextSelection& rSel ) const; - void ValidatePaM( TextPaM& rPaM ) const; - -public: - TextEngine(); - ~TextEngine(); - - void SetText( const String& rStr ); - String GetText( LineEnd aSeparator = LINEEND_LF ) const; - String GetText( const TextSelection& rSel, LineEnd aSeparator = LINEEND_LF ) const; - String GetTextLines( LineEnd aSeparator = LINEEND_LF ) const; - void ReplaceText(const TextSelection& rSel, const String& rText); - - sal_uLong GetTextLen( LineEnd aSeparator = LINEEND_LF ) const; - sal_uLong GetTextLen( const TextSelection& rSel, LineEnd aSeparator = LINEEND_LF ) const; - - void SetFont( const Font& rFont ); - const Font& GetFont() const { return maFont; } - - sal_uInt16 GetDefTab() const; - - void SetLeftMargin( sal_uInt16 n ); - sal_uInt16 GetLeftMargin() const; - - void SetUpdateMode( sal_Bool bUpdate ); - sal_Bool GetUpdateMode() const { return mbUpdate; } - - sal_uInt16 GetViewCount() const; - TextView* GetView( sal_uInt16 nView ) const; - void InsertView( TextView* pTextView ); - void RemoveView( TextView* pTextView ); - TextView* GetActiveView() const; - void SetActiveView( TextView* pView ); - - void SetMaxTextLen( sal_uLong nLen ); - sal_uLong GetMaxTextLen() const { return mnMaxTextLen; } - - void SetMaxTextWidth( sal_uLong nWidth ); - sal_uLong GetMaxTextWidth() const { return mnMaxTextWidth; } - - sal_uLong GetTextHeight() const; - sal_uLong CalcTextWidth(); - sal_uInt16 GetCharHeight() const { return mnCharHeight; } - - sal_uLong GetParagraphCount() const; - String GetText( sal_uLong nParagraph ) const; - sal_uInt16 GetTextLen( sal_uLong nParagraph ) const; - sal_uLong GetTextHeight( sal_uLong nParagraph ) const; - - sal_uInt16 GetLineCount( sal_uLong nParagraph ) const; - sal_uInt16 GetLineLen( sal_uLong nParagraph, sal_uInt16 nLine ) const; - - void SetRightToLeft( sal_Bool bR2L ); - sal_Bool IsRightToLeft() const { return mbRightToLeft; } - - sal_Bool HasUndoManager() const { return mpUndoManager ? sal_True : sal_False; } - ::svl::IUndoManager& - GetUndoManager(); - void UndoActionStart( sal_uInt16 nId = 0 ); - void UndoActionEnd(); - void InsertUndo( TextUndo* pUndo, sal_Bool bTryMerge = sal_False ); - sal_Bool IsInUndo() { return mbIsInUndo; } - void SetIsInUndo( sal_Bool bInUndo ) { mbIsInUndo = bInUndo; } - void ResetUndo(); - - void EnableUndo( sal_Bool bEnable ); - sal_Bool IsUndoEnabled() { return mbUndoEnabled; } - - void SetModified( sal_Bool bModified ) { mbModified = bModified; } - sal_Bool IsModified() const { return mbModified; } - - sal_Bool Read( SvStream& rInput, const TextSelection* pSel = NULL ); - - sal_Bool Write( SvStream& rOutput, const TextSelection* pSel = NULL, sal_Bool bHTML = sal_False ); - - TextPaM GetPaM( const Point& rDocPos, sal_Bool bSmart = sal_True ); - Rectangle PaMtoEditCursor( const TextPaM& rPaM, sal_Bool bSpecial = sal_False ); - String GetWord( const TextPaM& rCursorPos, TextPaM* pStartOfWord = 0 ); - - sal_Bool HasAttrib( sal_uInt16 nWhich ) const; - const TextAttrib* FindAttrib( const TextPaM& rPaM, sal_uInt16 nWhich ) const; - const TextCharAttrib* FindCharAttrib( const TextPaM& rPaM, sal_uInt16 nWhich ) const; - - void RemoveAttribs( sal_uLong nPara, sal_uInt16 nWhich, sal_Bool bIdleFormatAndUpdate ); - void RemoveAttrib( sal_uLong nPara, const TextCharAttrib& rAttrib ); - void RemoveAttribs( sal_uLong nPara, sal_Bool bIdleFormatAndUpdate = sal_True ); - void SetAttrib( const TextAttrib& rAttr, sal_uLong nPara, sal_uInt16 nStart, sal_uInt16 nEnd, sal_Bool bIdleFormatAndUpdate = sal_True ); - - TxtAlign GetTextAlign() const { return meAlign; } - void SetTextAlign( TxtAlign eAlign ); - - void Draw( OutputDevice* pDev, const Point& rPos ); - - void SetLocale( const ::com::sun::star::lang::Locale& rLocale ); - ::com::sun::star::lang::Locale GetLocale(); - ::com::sun::star::uno::Reference< ::com::sun::star::i18n::XBreakIterator > GetBreakIterator(); - - static sal_Bool DoesKeyChangeText( const KeyEvent& rKeyEvent ); - static sal_Bool IsSimpleCharInput( const KeyEvent& rKeyEvent ); -}; - -#endif // _TEXTENG_HXX - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svtools/inc/svtools/textview.hxx b/svtools/inc/svtools/textview.hxx deleted file mode 100644 index ebf7a4f..0000000 --- a/svtools/inc/svtools/textview.hxx +++ /dev/null @@ -1,217 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2000, 2010 Oracle and/or its affiliates. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * - * for a copy of the LGPLv3 License. - * - ************************************************************************/ - -#ifndef _TEXTVIEW_HXX -#define _TEXTVIEW_HXX - -#include "svtools/svtdllapi.h" -#include -#include -#include - -class TextEngine; -class OutputDevice; -class Window; -class Cursor; -class KeyEvent; -class MouseEvent; -class CommandEvent; -class TextSelFunctionSet; -class SelectionEngine; -class VirtualDevice; -struct TextDDInfo; - -namespace com { -namespace sun { -namespace star { -namespace datatransfer { -namespace clipboard { - class XClipboard; -}}}}} - -struct ImpTextView; - -class SVT_DLLPUBLIC TextView : public vcl::unohelper::DragAndDropClient -{ - friend class TextEngine; - friend class TextUndo; - friend class TextUndoManager; - friend class TextSelFunctionSet; - friend class ExtTextView; - -private: - ImpTextView* mpImpl; - - TextView( const TextView& ) : vcl::unohelper::DragAndDropClient() {} - TextView& operator=( const TextView& ) { return *this; } - -protected: - void ShowSelection(); - void HideSelection(); - void ShowSelection( const TextSelection& rSel ); - void ImpShowHideSelection( sal_Bool bShow, const TextSelection* pRange = NULL ); - - TextSelection ImpMoveCursor( const KeyEvent& rKeyEvent ); - TextPaM ImpDelete( sal_uInt8 nMode, sal_uInt8 nDelMode ); - void ImpSetSelection( const TextSelection& rNewSel, sal_Bool bUI ); - sal_Bool IsInSelection( const TextPaM& rPaM ); - - void ImpPaint( OutputDevice* pOut, const Point& rStartPos, Rectangle const* pPaintArea, TextSelection const* pPaintRange = 0, TextSelection const* pSelection = 0 ); - void ImpPaint( const Rectangle& rRect, sal_Bool bUseVirtDev ); - void ImpShowCursor( sal_Bool bGotoCursor, sal_Bool bForceVisCursor, sal_Bool bEndKey ); - void ImpHighlight( const TextSelection& rSel ); - void ImpSetSelection( const TextSelection& rSelection ); - Point ImpGetOutputStartPos( const Point& rStartDocPos ) const; - - void ImpHideDDCursor(); - void ImpShowDDCursor(); - - bool ImplTruncateNewText( rtl::OUString& rNewText ) const; - sal_Bool ImplCheckTextLen( const String& rNewText ); - - VirtualDevice* GetVirtualDevice(); - - // DragAndDropClient - virtual void dragGestureRecognized( const ::com::sun::star::datatransfer::dnd::DragGestureEvent& dge ) throw (::com::sun::star::uno::RuntimeException); - virtual void dragDropEnd( const ::com::sun::star::datatransfer::dnd::DragSourceDropEvent& dsde ) throw (::com::sun::star::uno::RuntimeException); - virtual void drop( const ::com::sun::star::datatransfer::dnd::DropTargetDropEvent& dtde ) throw (::com::sun::star::uno::RuntimeException); - virtual void dragEnter( const ::com::sun::star::datatransfer::dnd::DropTargetDragEnterEvent& dtdee ) throw (::com::sun::star::uno::RuntimeException); - virtual void dragExit( const ::com::sun::star::datatransfer::dnd::DropTargetEvent& dte ) throw (::com::sun::star::uno::RuntimeException); - virtual void dragOver( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& dtde ) throw (::com::sun::star::uno::RuntimeException); - - using DragAndDropClient::dragEnter; - using DragAndDropClient::dragExit; - using DragAndDropClient::dragOver; - -public: - TextView( TextEngine* pEng, Window* pWindow ); - virtual ~TextView(); - - TextEngine* GetTextEngine() const; - Window* GetWindow() const; - - void Invalidate(); - void Scroll( long nHorzScroll, long nVertScroll ); - - void ShowCursor( sal_Bool bGotoCursor = sal_True, sal_Bool bForceVisCursor = sal_True ); - void HideCursor(); - - void EnableCursor( sal_Bool bEnable ); - sal_Bool IsCursorEnabled() const; - - const TextSelection& GetSelection() const; - TextSelection& GetSelection(); - void SetSelection( const TextSelection& rNewSel ); - void SetSelection( const TextSelection& rNewSel, sal_Bool bGotoCursor ); - sal_Bool HasSelection() const; - - String GetSelected(); - String GetSelected( LineEnd aSeparator ); - void DeleteSelected(); - - void InsertNewText( const rtl::OUString& rNew, sal_Bool bSelect = sal_False ); - // deprecated: use InsertNewText instead - void InsertText( const String& rNew, sal_Bool bSelect = sal_False ); - - sal_Bool KeyInput( const KeyEvent& rKeyEvent ); - void Paint( const Rectangle& rRect ); - void MouseButtonUp( const MouseEvent& rMouseEvent ); - void MouseButtonDown( const MouseEvent& rMouseEvent ); - void MouseMove( const MouseEvent& rMouseEvent ); - void Command( const CommandEvent& rCEvt ); - - void Cut(); - void Copy(); - void Paste(); - - void Copy( ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboard >& rxClipboard ); - void Paste( ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboard >& rxClipboard ); - - void Undo(); - void Redo(); - - sal_Bool Read( SvStream& rInput ); - - void SetStartDocPos( const Point& rPos ); - const Point& GetStartDocPos() const; - - Point GetDocPos( const Point& rWindowPos ) const; - Point GetWindowPos( const Point& rDocPos ) const; - - void SetInsertMode( sal_Bool bInsert ); - sal_Bool IsInsertMode() const; - - void SetAutoIndentMode( sal_Bool bAutoIndent ); - - void SetReadOnly( sal_Bool bReadOnly ); - sal_Bool IsReadOnly() const; - - void SetAutoScroll( sal_Bool bAutoScroll ); - sal_Bool IsAutoScroll() const; - - sal_Bool SetCursorAtPoint( const Point& rPointPixel ); - sal_Bool IsSelectionAtPoint( const Point& rPointPixel ); - - void SetPaintSelection( sal_Bool bPaint); - - void EraseVirtualDevice(); - - // aus dem protected Teil hierher verschoben - // F�r 'SvtXECTextCursor' (TL). Mu� ggf nochmal anders gel�st werden. - TextPaM PageUp( const TextPaM& rPaM ); - TextPaM PageDown( const TextPaM& rPaM ); - TextPaM CursorUp( const TextPaM& rPaM ); - TextPaM CursorDown( const TextPaM& rPaM ); - TextPaM CursorLeft( const TextPaM& rPaM, sal_uInt16 nCharacterIteratorMode ); - TextPaM CursorRight( const TextPaM& rPaM, sal_uInt16 nCharacterIteratorMode ); - TextPaM CursorWordLeft( const TextPaM& rPaM ); - TextPaM CursorWordRight( const TextPaM& rPaM ); - TextPaM CursorStartOfLine( const TextPaM& rPaM ); - TextPaM CursorEndOfLine( const TextPaM& rPaM ); - TextPaM CursorStartOfParagraph( const TextPaM& rPaM ); - TextPaM CursorEndOfParagraph( const TextPaM& rPaM ); - TextPaM CursorStartOfDoc(); - TextPaM CursorEndOfDoc(); - - /** - Drag and Drop, deleting and selection regards all text that has an attribute - TEXTATTR_PROTECTED set as one entitity. Drag and dropped text is automatically - attibuted as protected. - */ - void SupportProtectAttribute(sal_Bool bSupport); - - /** - Returns the number in paragraph of the line in which the cursor is blinking - if enabled, -1 otherwise. - */ - sal_Int32 GetLineNumberOfCursorInSelection() const; -}; - -#endif // _TEXTVIEW_HXX - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svtools/inc/svtools/txtattr.hxx b/svtools/inc/svtools/txtattr.hxx deleted file mode 100644 index bf4c8e3..0000000 --- a/svtools/inc/svtools/txtattr.hxx +++ /dev/null @@ -1,236 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2000, 2010 Oracle and/or its affiliates. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * - * for a copy of the LGPLv3 License. - * - ************************************************************************/ - -#ifndef _TXTATTR_HXX -#define _TXTATTR_HXX - -#include "svtools/svtdllapi.h" -#include -#include -#include -#include - -class Font; - -#define TEXTATTR_INVALID 0 -#define TEXTATTR_FONTCOLOR 1 -#define TEXTATTR_HYPERLINK 2 -#define TEXTATTR_FONTWEIGHT 3 - -#define TEXTATTR_USER_START 1000 //start id for user defined text attributes -#define TEXTATTR_PROTECTED 4 - - -class SVT_DLLPUBLIC TextAttrib -{ -private: - sal_uInt16 mnWhich; - -protected: - TextAttrib( sal_uInt16 nWhich ) { mnWhich = nWhich; } - TextAttrib( const TextAttrib& rAttr ) { mnWhich = rAttr.mnWhich; } - -public: - - virtual ~TextAttrib(); - - sal_uInt16 Which() const { return mnWhich; } - virtual void SetFont( Font& rFont ) const = 0; - virtual TextAttrib* Clone() const = 0; - - virtual int operator==( const TextAttrib& rAttr ) const = 0; - int operator!=( const TextAttrib& rAttr ) const - { return !(*this == rAttr ); } -}; - - - -class SVT_DLLPUBLIC TextAttribFontColor : public TextAttrib -{ -private: - Color maColor; - -public: - TextAttribFontColor( const Color& rColor ); - TextAttribFontColor( const TextAttribFontColor& rAttr ); - ~TextAttribFontColor(); - - const Color& GetColor() const { return maColor; } - - virtual void SetFont( Font& rFont ) const; - virtual TextAttrib* Clone() const; - virtual int operator==( const TextAttrib& rAttr ) const; - -}; - -class SVT_DLLPUBLIC TextAttribFontWeight : public TextAttrib -{ -private: - FontWeight meWeight; - -public: - TextAttribFontWeight( FontWeight eWeight ); - TextAttribFontWeight( const TextAttribFontWeight& rAttr ); - ~TextAttribFontWeight(); - - virtual void SetFont( Font& rFont ) const; - virtual TextAttrib* Clone() const; - virtual int operator==( const TextAttrib& rAttr ) const; - - inline FontWeight getFontWeight() const { return meWeight; } -}; - - -class TextAttribHyperLink : public TextAttrib -{ -private: - XubString maURL; - XubString maDescription; - Color maColor; - -public: - TextAttribHyperLink( const TextAttribHyperLink& rAttr ); - ~TextAttribHyperLink(); - - void SetURL( const XubString& rURL ) { maURL = rURL; } - const XubString& GetURL() const { return maURL; } - - void SetDescription( const XubString& rDescr ) { maDescription = rDescr; } - const XubString& GetDescription() const { return maDescription; } - - void SetColor( const Color& rColor ) { maColor = rColor; } - const Color& GetColor() const { return maColor; } - - virtual void SetFont( Font& rFont ) const; - virtual TextAttrib* Clone() const; - virtual int operator==( const TextAttrib& rAttr ) const; -}; - -class SVT_DLLPUBLIC TextAttribProtect : public TextAttrib -{ -public: - TextAttribProtect(); - TextAttribProtect( const TextAttribProtect& rAttr ); - ~TextAttribProtect(); - - virtual void SetFont( Font& rFont ) const; - virtual TextAttrib* Clone() const; - virtual int operator==( const TextAttrib& rAttr ) const; - -}; - - -class TextCharAttrib -{ -private: - TextAttrib* mpAttr; - sal_uInt16 mnStart; - sal_uInt16 mnEnd; - -protected: - -public: - - TextCharAttrib( const TextAttrib& rAttr, sal_uInt16 nStart, sal_uInt16 nEnd ); - TextCharAttrib( const TextCharAttrib& rTextCharAttrib ); - ~TextCharAttrib(); - - const TextAttrib& GetAttr() const { return *mpAttr; } - - sal_uInt16 Which() const { return mpAttr->Which(); } - - sal_uInt16 GetStart() const { return mnStart; } - sal_uInt16& GetStart() { return mnStart; } - - sal_uInt16 GetEnd() const { return mnEnd; } - sal_uInt16& GetEnd() { return mnEnd; } - - inline sal_uInt16 GetLen() const; - - inline void MoveForward( sal_uInt16 nDiff ); - inline void MoveBackward( sal_uInt16 nDiff ); - - inline void Expand( sal_uInt16 nDiff ); - inline void Collaps( sal_uInt16 nDiff ); - - inline sal_Bool IsIn( sal_uInt16 nIndex ); - inline sal_Bool IsInside( sal_uInt16 nIndex ); - inline sal_Bool IsEmpty(); - -}; - -inline sal_uInt16 TextCharAttrib::GetLen() const -{ - DBG_ASSERT( mnEnd >= mnStart, "TextCharAttrib: nEnd < nStart!" ); - return mnEnd-mnStart; -} - -inline void TextCharAttrib::MoveForward( sal_uInt16 nDiff ) -{ - DBG_ASSERT( ((long)mnEnd + nDiff) <= 0xFFFF, "TextCharAttrib: MoveForward?!" ); - mnStart = mnStart + nDiff; - mnEnd = mnEnd + nDiff; -} - -inline void TextCharAttrib::MoveBackward( sal_uInt16 nDiff ) -{ - DBG_ASSERT( ((long)mnStart - nDiff) >= 0, "TextCharAttrib: MoveBackward?!" ); - mnStart = mnStart - nDiff; - mnEnd = mnEnd - nDiff; -} - -inline void TextCharAttrib::Expand( sal_uInt16 nDiff ) -{ - DBG_ASSERT( ( ((long)mnEnd + nDiff) <= (long)0xFFFF ), "TextCharAttrib: Expand?!" ); - mnEnd = mnEnd + nDiff; -} - -inline void TextCharAttrib::Collaps( sal_uInt16 nDiff ) -{ - DBG_ASSERT( (long)mnEnd - nDiff >= (long)mnStart, "TextCharAttrib: Collaps?!" ); - mnEnd = mnEnd - nDiff; -} - -inline sal_Bool TextCharAttrib::IsIn( sal_uInt16 nIndex ) -{ - return ( ( mnStart <= nIndex ) && ( mnEnd >= nIndex ) ); -} - -inline sal_Bool TextCharAttrib::IsInside( sal_uInt16 nIndex ) -{ - return ( ( mnStart < nIndex ) && ( mnEnd > nIndex ) ); -} - -inline sal_Bool TextCharAttrib::IsEmpty() -{ - return mnStart == mnEnd; -} - -#endif // _TXTATTR_HXX - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svtools/inc/svtools/xtextedt.hxx b/svtools/inc/svtools/xtextedt.hxx deleted file mode 100644 index b0b09b0..0000000 --- a/svtools/inc/svtools/xtextedt.hxx +++ /dev/null @@ -1,69 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ -#ifndef _XTEXTEDT_HXX -#define _XTEXTEDT_HXX - -#include "svtools/svtdllapi.h" -#include -#include - -namespace com { -namespace sun { -namespace star { -namespace util { - struct SearchOptions; -}}}} - -class SVT_DLLPUBLIC ExtTextEngine : public TextEngine -{ -private: - String maGroupChars; - -public: - ExtTextEngine(); - ~ExtTextEngine(); - - const String& GetGroupChars() const { return maGroupChars; } - void SetGroupChars( const String& r ) { maGroupChars = r; } - TextSelection MatchGroup( const TextPaM& rCursor ) const; - - sal_Bool Search( TextSelection& rSel, const ::com::sun::star::util::SearchOptions& rSearchOptions, sal_Bool bForward = sal_True ); -}; - -class SVT_DLLPUBLIC ExtTextView : public TextView -{ -protected: - sal_Bool ImpIndentBlock( sal_Bool bRight ); - -public: - ExtTextView( ExtTextEngine* pEng, Window* pWindow ); - ~ExtTextView(); - - sal_Bool MatchGroup(); - - sal_Bool Search( const ::com::sun::star::util::SearchOptions& rSearchOptions, sal_Bool bForward ); - sal_uInt16 Replace( const ::com::sun::star::util::SearchOptions& rSearchOptions, sal_Bool bAll, sal_Bool bForward ); - - sal_Bool IndentBlock(); - sal_Bool UnindentBlock(); -}; - -#endif // _XTEXTEDT_HXX - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svtools/source/brwbox/ebbcontrols.cxx b/svtools/source/brwbox/ebbcontrols.cxx index b0ab801..bf818c2 100644 --- a/svtools/source/brwbox/ebbcontrols.cxx +++ b/svtools/source/brwbox/ebbcontrols.cxx @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include diff --git a/svtools/source/contnr/DocumentInfoPreview.cxx b/svtools/source/contnr/DocumentInfoPreview.cxx index b27df17..3f3f15a 100644 --- a/svtools/source/contnr/DocumentInfoPreview.cxx +++ b/svtools/source/contnr/DocumentInfoPreview.cxx @@ -38,7 +38,7 @@ #include "svl/inettype.hxx" #include "svtools/DocumentInfoPreview.hxx" #include "svtools/imagemgr.hxx" -#include "svtools/txtattr.hxx" +#include "vcl/txtattr.hxx" #include "tools/datetime.hxx" #include "tools/urlobj.hxx" #include "unotools/pathoptions.hxx" diff --git a/svtools/source/contnr/templwin.cxx b/svtools/source/contnr/templwin.cxx index 937236f..301967a 100644 --- a/svtools/source/contnr/templwin.cxx +++ b/svtools/source/contnr/templwin.cxx @@ -33,13 +33,13 @@ #include #include #include -#include +#include #include #include #include #include #include -#include +#include #include #include "templwin.hrc" #include diff --git a/svtools/source/edit/editsyntaxhighlighter.cxx b/svtools/source/edit/editsyntaxhighlighter.cxx index 20749db..18361d3 100644 --- a/svtools/source/edit/editsyntaxhighlighter.cxx +++ b/svtools/source/edit/editsyntaxhighlighter.cxx @@ -28,9 +28,9 @@ #include -#include +#include #include -#include +#include MultiLineEditSyntaxHighlight::MultiLineEditSyntaxHighlight( Window* pParent, WinBits nWinStyle, diff --git a/svtools/source/edit/svmedit.cxx b/svtools/source/edit/svmedit.cxx index 4fff9e0..24e97ec 100644 --- a/svtools/source/edit/svmedit.cxx +++ b/svtools/source/edit/svmedit.cxx @@ -26,1593 +26,38 @@ * ************************************************************************/ -#include -#include "unoiface.hxx" - -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - - -// IDs erstmal aus VCL geklaut, muss mal richtig delivert werden... -#define SV_MENU_EDIT_UNDO 1 -#define SV_MENU_EDIT_CUT 2 -#define SV_MENU_EDIT_COPY 3 -#define SV_MENU_EDIT_PASTE 4 -#define SV_MENU_EDIT_DELETE 5 -#define SV_MENU_EDIT_SELECTALL 6 -#define SV_MENU_EDIT_INSERTSYMBOL 7 -#include - -namespace css = ::com::sun::star; - -class TextWindow : public Window -{ -private: - ExtTextEngine* mpExtTextEngine; - ExtTextView* mpExtTextView; - - sal_Bool mbInMBDown; - sal_Bool mbFocusSelectionHide; - sal_Bool mbIgnoreTab; - sal_Bool mbActivePopup; - sal_Bool mbSelectOnTab; - sal_Bool mbTextSelectable; - -public: - TextWindow( Window* pParent ); - ~TextWindow(); - - ExtTextEngine* GetTextEngine() const { return mpExtTextEngine; } - ExtTextView* GetTextView() const { return mpExtTextView; } - - virtual void MouseMove( const MouseEvent& rMEvt ); - virtual void MouseButtonDown( const MouseEvent& rMEvt ); - virtual void MouseButtonUp( const MouseEvent& rMEvt ); - virtual void KeyInput( const KeyEvent& rKEvent ); - - virtual void Command( const CommandEvent& rCEvt ); - - virtual void Paint( const Rectangle& rRect ); - virtual void Resize(); - - virtual void GetFocus(); - virtual void LoseFocus(); - - sal_Bool IsAutoFocusHide() const { return mbFocusSelectionHide; } - void SetAutoFocusHide( sal_Bool bAutoHide ) { mbFocusSelectionHide = bAutoHide; } - - sal_Bool IsIgnoreTab() const { return mbIgnoreTab; } - void SetIgnoreTab( sal_Bool bIgnore ) { mbIgnoreTab = bIgnore; } - - void DisableSelectionOnFocus() { mbSelectOnTab = sal_False; } - - void SetTextSelectable( sal_Bool bTextSelectable ) { mbTextSelectable = bTextSelectable; } - - virtual - ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindowPeer > - GetComponentInterface(sal_Bool bCreate = sal_True); -}; - - -class ImpSvMEdit : public SfxListener -{ -private: - MultiLineEdit* pSvMultiLineEdit; - - TextWindow* mpTextWindow; - ScrollBar* mpHScrollBar; - ScrollBar* mpVScrollBar; - ScrollBarBox* mpScrollBox; - - Point maTextWindowOffset; - xub_StrLen mnTextWidth; - mutable Selection maSelection; - -protected: - virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ); - void ImpUpdateSrollBarVis( WinBits nWinStyle ); - void ImpInitScrollBars(); - void ImpSetScrollBarRanges(); - void ImpSetHScrollBarThumbPos(); - DECL_LINK( ScrollHdl, ScrollBar* ); - -public: - ImpSvMEdit( MultiLineEdit* pSvMultiLineEdit, WinBits nWinStyle ); - ~ImpSvMEdit(); - - void SetModified( sal_Bool bMod ); - sal_Bool IsModified() const; - - void SetReadOnly( sal_Bool bRdOnly ); - sal_Bool IsReadOnly() const; - - void SetMaxTextLen( xub_StrLen nLen ); - xub_StrLen GetMaxTextLen() const; - - sal_Bool IsInsertMode() const; - - void InsertText( const String& rStr ); - String GetSelected() const; - String GetSelected( LineEnd aSeparator ) const; - - void SetSelection( const Selection& rSelection ); - const Selection& GetSelection() const; - - void Cut(); - void Copy(); - void Paste(); - - void SetText( const String& rStr ); - String GetText() const; - String GetText( LineEnd aSeparator ) const; - String GetTextLines( LineEnd aSeparator ) const; - - void Resize(); - void GetFocus(); - - sal_Bool HandleCommand( const CommandEvent& rCEvt ); - - void Enable( sal_Bool bEnable ); - - Size CalcMinimumSize() const; - Size CalcSize( sal_uInt16 nColumns, sal_uInt16 nLines ) const; - void GetMaxVisColumnsAndLines( sal_uInt16& rnCols, sal_uInt16& rnLines ) const; - - void SetAlign( WinBits nWinStyle ); - - void InitFromStyle( WinBits nWinStyle ); - - TextWindow* GetTextWindow() { return mpTextWindow; } - ScrollBar* GetHScrollBar() { return mpHScrollBar; } - ScrollBar* GetVScrollBar() { return mpVScrollBar; } -}; - -ImpSvMEdit::ImpSvMEdit( MultiLineEdit* pEdt, WinBits nWinStyle ) - :mpHScrollBar(NULL) - ,mpVScrollBar(NULL) - ,mpScrollBox(NULL) -{ - pSvMultiLineEdit = pEdt; - mnTextWidth = 0; - mpTextWindow = new TextWindow( pEdt ); - mpTextWindow->Show(); - InitFromStyle( nWinStyle ); - StartListening( *mpTextWindow->GetTextEngine() ); -} - -void ImpSvMEdit::ImpUpdateSrollBarVis( WinBits nWinStyle ) -{ - const sal_Bool bHaveVScroll = (NULL != mpVScrollBar); - const sal_Bool bHaveHScroll = (NULL != mpHScrollBar); - const sal_Bool bHaveScrollBox = (NULL != mpScrollBox); - - sal_Bool bNeedVScroll = ( nWinStyle & WB_VSCROLL ) == WB_VSCROLL; - const sal_Bool bNeedHScroll = ( nWinStyle & WB_HSCROLL ) == WB_HSCROLL; - - const sal_Bool bAutoVScroll = ( nWinStyle & WB_AUTOVSCROLL ) == WB_AUTOVSCROLL; - if ( !bNeedVScroll && bAutoVScroll ) - { - TextEngine& rEngine( *mpTextWindow->GetTextEngine() ); - sal_uLong nOverallTextHeight(0); - for ( sal_uLong i=0; i (sal_uLong)mpTextWindow->GetOutputSizePixel().Height() ) - bNeedVScroll = true; - } - - const sal_Bool bNeedScrollBox = bNeedVScroll && bNeedHScroll; - - sal_Bool bScrollbarsChanged = false; - if ( bHaveVScroll != bNeedVScroll ) - { - delete mpVScrollBar; - mpVScrollBar = bNeedVScroll ? new ScrollBar( pSvMultiLineEdit, WB_VSCROLL|WB_DRAG ) : NULL; - - if ( bNeedVScroll ) - { - mpVScrollBar->Show(); - mpVScrollBar->SetScrollHdl( LINK( this, ImpSvMEdit, ScrollHdl ) ); - } - - bScrollbarsChanged = sal_True; - } - - if ( bHaveHScroll != bNeedHScroll ) - { - delete mpHScrollBar; - mpHScrollBar = bNeedHScroll ? new ScrollBar( pSvMultiLineEdit, WB_HSCROLL|WB_DRAG ) : NULL; - - if ( bNeedHScroll ) - { - mpHScrollBar->Show(); - mpHScrollBar->SetScrollHdl( LINK( this, ImpSvMEdit, ScrollHdl ) ); - } - - bScrollbarsChanged = sal_True; - } - - if ( bHaveScrollBox != bNeedScrollBox ) - { - delete mpScrollBox; - mpScrollBox = bNeedScrollBox ? new ScrollBarBox( pSvMultiLineEdit, WB_SIZEABLE ) : NULL; - - if ( bNeedScrollBox ) - mpScrollBox->Show(); - } - - if ( bScrollbarsChanged ) - { - ImpInitScrollBars(); - Resize(); - } -} - -void ImpSvMEdit::InitFromStyle( WinBits nWinStyle ) -{ - ImpUpdateSrollBarVis( nWinStyle ); - SetAlign( nWinStyle ); - - if ( nWinStyle & WB_NOHIDESELECTION ) - mpTextWindow->SetAutoFocusHide( sal_False ); - else - mpTextWindow->SetAutoFocusHide( sal_True ); - - if ( nWinStyle & WB_READONLY ) - mpTextWindow->GetTextView()->SetReadOnly( sal_True ); - else - mpTextWindow->GetTextView()->SetReadOnly( sal_False ); - - if ( nWinStyle & WB_IGNORETAB ) - { - mpTextWindow->SetIgnoreTab( sal_True ); - } - else - { - mpTextWindow->SetIgnoreTab( sal_False ); - // #103667# MultiLineEdit has the flag, but focusable window also needs this flag - WinBits nStyle = mpTextWindow->GetStyle(); - nStyle |= WINDOW_DLGCTRL_MOD1TAB; - mpTextWindow->SetStyle( nStyle ); - } -} - -ImpSvMEdit::~ImpSvMEdit() -{ - EndListening( *mpTextWindow->GetTextEngine() ); - delete mpTextWindow; - delete mpHScrollBar; - delete mpVScrollBar; - delete mpScrollBox; -} - -void ImpSvMEdit::ImpSetScrollBarRanges() -{ - if ( mpVScrollBar ) - { - sal_uLong nTextHeight = mpTextWindow->GetTextEngine()->GetTextHeight(); - mpVScrollBar->SetRange( Range( 0, (long)nTextHeight-1 ) ); - } - if ( mpHScrollBar ) - { -// sal_uLong nTextWidth = mpTextWindow->GetTextEngine()->CalcTextWidth(); - // Es gibt kein Notify bei Breiten-Aenderung... -// sal_uLong nW = Max( (sal_uLong)mpTextWindow->GetOutputSizePixel().Width()*5, (sal_uLong)nTextWidth ); -// mpHScrollBar->SetRange( Range( 0, (long)nW ) ); - mpHScrollBar->SetRange( Range( 0, (long)mnTextWidth-1 ) ); - } -} - -void ImpSvMEdit::ImpInitScrollBars() -{ - static const sal_Unicode sampleChar = { 'x' }; - if ( mpHScrollBar || mpVScrollBar ) - { - ImpSetScrollBarRanges(); - Size aCharBox; - aCharBox.Width() = mpTextWindow->GetTextWidth( rtl::OUString(sampleChar) ); - aCharBox.Height() = mpTextWindow->GetTextHeight(); - Size aOutSz = mpTextWindow->GetOutputSizePixel(); - if ( mpHScrollBar ) - { - mpHScrollBar->SetVisibleSize( aOutSz.Width() ); - mpHScrollBar->SetPageSize( aOutSz.Width() * 8 / 10 ); - mpHScrollBar->SetLineSize( aCharBox.Width()*10 ); - ImpSetHScrollBarThumbPos(); - } - if ( mpVScrollBar ) - { - mpVScrollBar->SetVisibleSize( aOutSz.Height() ); - mpVScrollBar->SetPageSize( aOutSz.Height() * 8 / 10 ); - mpVScrollBar->SetLineSize( aCharBox.Height() ); - mpVScrollBar->SetThumbPos( mpTextWindow->GetTextView()->GetStartDocPos().Y() ); - } - } -} - -void ImpSvMEdit::ImpSetHScrollBarThumbPos() -{ - long nX = mpTextWindow->GetTextView()->GetStartDocPos().X(); - if ( !mpTextWindow->GetTextEngine()->IsRightToLeft() ) - mpHScrollBar->SetThumbPos( nX ); - else - mpHScrollBar->SetThumbPos( mnTextWidth - mpHScrollBar->GetVisibleSize() - nX ); - -} - -IMPL_LINK( ImpSvMEdit, ScrollHdl, ScrollBar*, pCurScrollBar ) -{ - long nDiffX = 0, nDiffY = 0; - - if ( pCurScrollBar == mpVScrollBar ) - nDiffY = mpTextWindow->GetTextView()->GetStartDocPos().Y() - pCurScrollBar->GetThumbPos(); - else if ( pCurScrollBar == mpHScrollBar ) - nDiffX = mpTextWindow->GetTextView()->GetStartDocPos().X() - pCurScrollBar->GetThumbPos(); - - mpTextWindow->GetTextView()->Scroll( nDiffX, nDiffY ); - // mpTextWindow->GetTextView()->ShowCursor( sal_False, sal_True ); - - return 0; -} - - -// void ImpSvMEdit::ImpModified() -// { -// // Wann wird das gerufen ????????????????????? -// pSvMultiLineEdit->Modify(); -// } - -void ImpSvMEdit::SetAlign( WinBits nWinStyle ) -{ - sal_Bool bRTL = Application::GetSettings().GetLayoutRTL(); - mpTextWindow->GetTextEngine()->SetRightToLeft( bRTL ); - - if ( nWinStyle & WB_CENTER ) - mpTextWindow->GetTextEngine()->SetTextAlign( TXTALIGN_CENTER ); - else if ( nWinStyle & WB_RIGHT ) - mpTextWindow->GetTextEngine()->SetTextAlign( !bRTL ? TXTALIGN_RIGHT : TXTALIGN_LEFT ); - else if ( nWinStyle & WB_LEFT ) - mpTextWindow->GetTextEngine()->SetTextAlign( !bRTL ? TXTALIGN_LEFT : TXTALIGN_RIGHT ); -} - -void ImpSvMEdit::SetModified( sal_Bool bMod ) -{ - mpTextWindow->GetTextEngine()->SetModified( bMod ); -} - -sal_Bool ImpSvMEdit::IsModified() const -{ - return mpTextWindow->GetTextEngine()->IsModified(); -} - -void ImpSvMEdit::SetReadOnly( sal_Bool bRdOnly ) -{ - mpTextWindow->GetTextView()->SetReadOnly( bRdOnly ); - // Farbe anpassen ??????????????????????????? -} - -sal_Bool ImpSvMEdit::IsReadOnly() const -{ - return mpTextWindow->GetTextView()->IsReadOnly(); -} - -void ImpSvMEdit::SetMaxTextLen( xub_StrLen nLen ) -{ - mpTextWindow->GetTextEngine()->SetMaxTextLen( nLen ); -} - -xub_StrLen ImpSvMEdit::GetMaxTextLen() const -{ - return sal::static_int_cast< xub_StrLen >( - mpTextWindow->GetTextEngine()->GetMaxTextLen()); -} - -void ImpSvMEdit::InsertText( const String& rStr ) -{ - mpTextWindow->GetTextView()->InsertText( rStr ); -} - -String ImpSvMEdit::GetSelected() const -{ - return mpTextWindow->GetTextView()->GetSelected(); -} - -String ImpSvMEdit::GetSelected( LineEnd aSeparator ) const -{ - return mpTextWindow->GetTextView()->GetSelected( aSeparator ); -} - -void ImpSvMEdit::Resize() -{ - size_t nIteration = 1; - do - { - WinBits nWinStyle( pSvMultiLineEdit->GetStyle() ); - if ( ( nWinStyle & WB_AUTOVSCROLL ) == WB_AUTOVSCROLL ) - ImpUpdateSrollBarVis( nWinStyle ); - - Size aSz = pSvMultiLineEdit->GetOutputSizePixel(); - Size aEditSize = aSz; - long nSBWidth = pSvMultiLineEdit->GetSettings().GetStyleSettings().GetScrollBarSize(); - nSBWidth = pSvMultiLineEdit->CalcZoom( nSBWidth ); - - if ( mpHScrollBar ) - aSz.Height() -= nSBWidth+1; - if ( mpVScrollBar ) - aSz.Width() -= nSBWidth+1; - - if ( !mpHScrollBar ) - mpTextWindow->GetTextEngine()->SetMaxTextWidth( aSz.Width() ); - else - mpHScrollBar->SetPosSizePixel( 0, aEditSize.Height()-nSBWidth, aSz.Width(), nSBWidth ); - - Point aTextWindowPos( maTextWindowOffset ); - if ( mpVScrollBar ) - { - if( Application::GetSettings().GetLayoutRTL() ) - { - mpVScrollBar->SetPosSizePixel( 0, 0, nSBWidth, aSz.Height() ); - aTextWindowPos.X() += nSBWidth; - } - else - mpVScrollBar->SetPosSizePixel( aEditSize.Width()-nSBWidth, 0, nSBWidth, aSz.Height() ); - } - - if ( mpScrollBox ) - mpScrollBox->SetPosSizePixel( aSz.Width(), aSz.Height(), nSBWidth, nSBWidth ); - - Size aTextWindowSize( aSz ); - aTextWindowSize.Width() -= maTextWindowOffset.X(); - aTextWindowSize.Height() -= maTextWindowOffset.Y(); - if ( aTextWindowSize.Width() < 0 ) - aTextWindowSize.Width() = 0; - if ( aTextWindowSize.Height() < 0 ) - aTextWindowSize.Height() = 0; - - Size aOldTextWindowSize( mpTextWindow->GetSizePixel() ); - mpTextWindow->SetPosSizePixel( aTextWindowPos, aTextWindowSize ); - if ( aOldTextWindowSize == aTextWindowSize ) - break; - - // Changing the text window size might effectively have changed the need for - // scrollbars, so do another iteration. - ++nIteration; - OSL_ENSURE( nIteration < 3, "ImpSvMEdit::Resize: isn't this expected to terminate with the second iteration?" ); - - } while ( nIteration <= 3 ); // artificial break after four iterations - - ImpInitScrollBars(); -} - -void ImpSvMEdit::GetFocus() -{ - mpTextWindow->GrabFocus(); -} - -void ImpSvMEdit::Cut() -{ - if ( !mpTextWindow->GetTextView()->IsReadOnly() ) - mpTextWindow->GetTextView()->Cut(); -} - -void ImpSvMEdit::Copy() -{ - mpTextWindow->GetTextView()->Copy(); -} - -void ImpSvMEdit::Paste() -{ - if ( !mpTextWindow->GetTextView()->IsReadOnly() ) - mpTextWindow->GetTextView()->Paste(); -} - -void ImpSvMEdit::SetText( const String& rStr ) -{ - sal_Bool bWasModified = mpTextWindow->GetTextEngine()->IsModified(); - mpTextWindow->GetTextEngine()->SetText( rStr ); - if ( !bWasModified ) - mpTextWindow->GetTextEngine()->SetModified( sal_False ); - - mpTextWindow->GetTextView()->SetSelection( TextSelection() ); - - WinBits nWinStyle( pSvMultiLineEdit->GetStyle() ); - if ( ( nWinStyle & WB_AUTOVSCROLL ) == WB_AUTOVSCROLL ) - ImpUpdateSrollBarVis( nWinStyle ); -} - -String ImpSvMEdit::GetText() const -{ - return mpTextWindow->GetTextEngine()->GetText(); -} - -String ImpSvMEdit::GetText( LineEnd aSeparator ) const -{ - return mpTextWindow->GetTextEngine()->GetText( aSeparator ); -} - -String ImpSvMEdit::GetTextLines( LineEnd aSeparator ) const -{ - return mpTextWindow->GetTextEngine()->GetTextLines( aSeparator ); -} - -void ImpSvMEdit::Notify( SfxBroadcaster&, const SfxHint& rHint ) -{ - if ( rHint.ISA( TextHint ) ) - { - const TextHint& rTextHint = (const TextHint&)rHint; - if( rTextHint.GetId() == TEXT_HINT_VIEWSCROLLED ) - { - if ( mpHScrollBar ) - ImpSetHScrollBarThumbPos(); - if ( mpVScrollBar ) - mpVScrollBar->SetThumbPos( mpTextWindow->GetTextView()->GetStartDocPos().Y() ); - } - else if( rTextHint.GetId() == TEXT_HINT_TEXTHEIGHTCHANGED ) - { - if ( mpTextWindow->GetTextView()->GetStartDocPos().Y() ) - { - long nOutHeight = mpTextWindow->GetOutputSizePixel().Height(); - long nTextHeight = mpTextWindow->GetTextEngine()->GetTextHeight(); - if ( nTextHeight < nOutHeight ) - mpTextWindow->GetTextView()->Scroll( 0, mpTextWindow->GetTextView()->GetStartDocPos().Y() ); - } - - ImpSetScrollBarRanges(); - } - else if( rTextHint.GetId() == TEXT_HINT_TEXTFORMATTED ) - { - if ( mpHScrollBar ) - { - sal_uLong nWidth = mpTextWindow->GetTextEngine()->CalcTextWidth(); - if ( nWidth != mnTextWidth ) - { - mnTextWidth = sal::static_int_cast< xub_StrLen >(nWidth); - mpHScrollBar->SetRange( Range( 0, (long)mnTextWidth-1 ) ); - ImpSetHScrollBarThumbPos(); - } - } - } - else if( rTextHint.GetId() == TEXT_HINT_MODIFIED ) - { - pSvMultiLineEdit->Modify(); - } - } -} - -void ImpSvMEdit::SetSelection( const Selection& rSelection ) -{ - String aText = mpTextWindow->GetTextEngine()->GetText(); - - Selection aNewSelection( rSelection ); - if ( aNewSelection.Min() < 0 ) - aNewSelection.Min() = 0; - else if ( aNewSelection.Min() > aText.Len() ) - aNewSelection.Min() = aText.Len(); - if ( aNewSelection.Max() < 0 ) - aNewSelection.Max() = 0; - else if ( aNewSelection.Max() > aText.Len() ) - aNewSelection.Max() = aText.Len(); - - long nEnd = Max( aNewSelection.Min(), aNewSelection.Max() ); - TextSelection aTextSel; - sal_uLong nPara = 0; - sal_uInt16 nChar = 0; - sal_uInt16 x = 0; - while ( x <= nEnd ) - { - if ( x == aNewSelection.Min() ) - aTextSel.GetStart() = TextPaM( nPara, nChar ); - if ( x == aNewSelection.Max() ) - aTextSel.GetEnd() = TextPaM( nPara, nChar ); - - if ( ( x < aText.Len() ) && ( aText.GetChar( x ) == '\n' ) ) - { - nPara++; - nChar = 0; - } - else - nChar++; - x++; - } - mpTextWindow->GetTextView()->SetSelection( aTextSel ); -} - -const Selection& ImpSvMEdit::GetSelection() const -{ - maSelection = Selection(); - TextSelection aTextSel( mpTextWindow->GetTextView()->GetSelection() ); - aTextSel.Justify(); - // Selektion flachklopfen => jeder Umbruch ein Zeichen... - - ExtTextEngine* pExtTextEngine = mpTextWindow->GetTextEngine(); - // Absaetze davor: - sal_uLong n; - for ( n = 0; n < aTextSel.GetStart().GetPara(); n++ ) - { - maSelection.Min() += pExtTextEngine->GetTextLen( n ); - maSelection.Min()++; - } - - // Erster Absatz mit Selektion: - maSelection.Max() = maSelection.Min(); - maSelection.Min() += aTextSel.GetStart().GetIndex(); - - for ( n = aTextSel.GetStart().GetPara(); n < aTextSel.GetEnd().GetPara(); n++ ) - { - maSelection.Max() += pExtTextEngine->GetTextLen( n ); - maSelection.Max()++; - } - - maSelection.Max() += aTextSel.GetEnd().GetIndex(); - - return maSelection; -} - -Size ImpSvMEdit::CalcMinimumSize() const -{ - Size aSz( mpTextWindow->GetTextEngine()->CalcTextWidth(), - mpTextWindow->GetTextEngine()->GetTextHeight() ); - - if ( mpHScrollBar ) - aSz.Height() += mpHScrollBar->GetSizePixel().Height(); - if ( mpVScrollBar ) - aSz.Width() += mpVScrollBar->GetSizePixel().Width(); - - return aSz; -} - -Size ImpSvMEdit::CalcSize( sal_uInt16 nColumns, sal_uInt16 nLines ) const -{ - static const sal_Unicode sampleChar = 'X'; - - Size aSz; - Size aCharSz; - aCharSz.Width() = mpTextWindow->GetTextWidth( rtl::OUString(sampleChar) ); - aCharSz.Height() = mpTextWindow->GetTextHeight(); - - if ( nLines ) - aSz.Height() = nLines*aCharSz.Height(); - else - aSz.Height() = mpTextWindow->GetTextEngine()->GetTextHeight(); - - if ( nColumns ) - aSz.Width() = nColumns*aCharSz.Width(); - else - aSz.Width() = mpTextWindow->GetTextEngine()->CalcTextWidth(); - - if ( mpHScrollBar ) - aSz.Height() += mpHScrollBar->GetSizePixel().Height(); - if ( mpVScrollBar ) - aSz.Width() += mpVScrollBar->GetSizePixel().Width(); - - return aSz; -} - -void ImpSvMEdit::GetMaxVisColumnsAndLines( sal_uInt16& rnCols, sal_uInt16& rnLines ) const -{ - static const sal_Unicode sampleChar = { 'x' }; - Size aOutSz = mpTextWindow->GetOutputSizePixel(); - Size aCharSz( mpTextWindow->GetTextWidth( rtl::OUString(sampleChar) ), mpTextWindow->GetTextHeight() ); - rnCols = (sal_uInt16) (aOutSz.Width()/aCharSz.Width()); - rnLines = (sal_uInt16) (aOutSz.Height()/aCharSz.Height()); -} - -void ImpSvMEdit::Enable( sal_Bool bEnable ) -{ - mpTextWindow->Enable( bEnable ); - if ( mpHScrollBar ) - mpHScrollBar->Enable( bEnable ); - if ( mpVScrollBar ) - mpVScrollBar->Enable( bEnable ); -} - -sal_Bool ImpSvMEdit::HandleCommand( const CommandEvent& rCEvt ) -{ - sal_Bool bDone = sal_False; - if ( ( rCEvt.GetCommand() == COMMAND_WHEEL ) || - ( rCEvt.GetCommand() == COMMAND_STARTAUTOSCROLL ) || - ( rCEvt.GetCommand() == COMMAND_AUTOSCROLL ) ) - { - mpTextWindow->HandleScrollCommand( rCEvt, mpHScrollBar, mpVScrollBar ); - bDone = sal_True; - } - return bDone; -} - - -TextWindow::TextWindow( Window* pParent ) : Window( pParent ) -{ - mbInMBDown = sal_False; - mbSelectOnTab = sal_True; - mbFocusSelectionHide = sal_False; - mbIgnoreTab = sal_False; - mbActivePopup = sal_False; - mbSelectOnTab = sal_True; - mbTextSelectable = sal_True; - - SetPointer( Pointer( POINTER_TEXT ) ); - - mpExtTextEngine = new ExtTextEngine; - mpExtTextEngine->SetMaxTextLen( STRING_MAXLEN ); - if( pParent->GetStyle() & WB_BORDER ) - mpExtTextEngine->SetLeftMargin( 2 ); - mpExtTextEngine->SetLocale( GetSettings().GetLocale() ); - mpExtTextView = new ExtTextView( mpExtTextEngine, this ); - mpExtTextEngine->InsertView( mpExtTextView ); - mpExtTextEngine->EnableUndo( sal_True ); - mpExtTextView->ShowCursor(); - - Color aBackgroundColor = GetSettings().GetStyleSettings().GetWorkspaceColor(); - SetBackground( aBackgroundColor ); - pParent->SetBackground( aBackgroundColor ); -} - -TextWindow::~TextWindow() -{ - delete mpExtTextView; - delete mpExtTextEngine; -} - -void TextWindow::MouseMove( const MouseEvent& rMEvt ) -{ - mpExtTextView->MouseMove( rMEvt ); - Window::MouseMove( rMEvt ); -} - -void TextWindow::MouseButtonDown( const MouseEvent& rMEvt ) -{ - if ( !mbTextSelectable ) - return; - - mbInMBDown = sal_True; // Dann im GetFocus nicht alles selektieren wird - mpExtTextView->MouseButtonDown( rMEvt ); - Window::MouseButtonDown( rMEvt ); - GrabFocus(); - mbInMBDown = sal_False; -} - -void TextWindow::MouseButtonUp( const MouseEvent& rMEvt ) -{ - mpExtTextView->MouseButtonUp( rMEvt ); - Window::MouseButtonUp( rMEvt ); -} - -void TextWindow::KeyInput( const KeyEvent& rKEvent ) -{ - sal_Bool bDone = sal_False; - sal_uInt16 nCode = rKEvent.GetKeyCode().GetCode(); - if ( nCode == com::sun::star::awt::Key::SELECT_ALL || - ( (nCode == KEY_A) && rKEvent.GetKeyCode().IsMod1() && !rKEvent.GetKeyCode().IsMod2() ) - ) - { - mpExtTextView->SetSelection( TextSelection( TextPaM( 0, 0 ), TextPaM( 0xFFFF, 0xFFFF ) ) ); - bDone = sal_True; - } - else if ( (nCode == KEY_S) && rKEvent.GetKeyCode().IsShift() && rKEvent.GetKeyCode().IsMod1() ) - { - if ( Edit::GetGetSpecialCharsFunction() ) - { - // Damit die Selektion erhalten bleibt - mbActivePopup = sal_True; - rtl::OUString aChars = Edit::GetGetSpecialCharsFunction()( this, GetFont() ); - if (!aChars.isEmpty()) - { - mpExtTextView->InsertText( aChars ); - mpExtTextView->GetTextEngine()->SetModified( sal_True ); - } - mbActivePopup = sal_False; - bDone = sal_True; - } - } - else if ( nCode == KEY_TAB ) - { - if ( !mbIgnoreTab || rKEvent.GetKeyCode().IsMod1() ) - bDone = mpExtTextView->KeyInput( rKEvent ); - } - else - { - bDone = mpExtTextView->KeyInput( rKEvent ); - } - if ( !bDone ) - Window::KeyInput( rKEvent ); -} - -void TextWindow::Paint( const Rectangle& rRect ) -{ - mpExtTextView->Paint( rRect ); -} - -void TextWindow::Resize() -{ -} - -void TextWindow::Command( const CommandEvent& rCEvt ) -{ - if ( rCEvt.GetCommand() == COMMAND_CONTEXTMENU ) - { - PopupMenu* pPopup = Edit::CreatePopupMenu(); - if ( !mpExtTextView->HasSelection() ) - { - pPopup->EnableItem( SV_MENU_EDIT_CUT, sal_False ); - pPopup->EnableItem( SV_MENU_EDIT_COPY, sal_False ); - pPopup->EnableItem( SV_MENU_EDIT_DELETE, sal_False ); - } - if ( mpExtTextView->IsReadOnly() ) - { - pPopup->EnableItem( SV_MENU_EDIT_CUT, sal_False ); - pPopup->EnableItem( SV_MENU_EDIT_PASTE, sal_False ); - pPopup->EnableItem( SV_MENU_EDIT_DELETE, sal_False ); - pPopup->EnableItem( SV_MENU_EDIT_INSERTSYMBOL, sal_False ); - } - if ( !mpExtTextView->GetTextEngine()->HasUndoManager() || !mpExtTextView->GetTextEngine()->GetUndoManager().GetUndoActionCount() ) - { - pPopup->EnableItem( SV_MENU_EDIT_UNDO, sal_False ); - } -// if ( ( maSelection.Min() == 0 ) && ( maSelection.Max() == maText.Len() ) ) -// { -// pPopup->EnableItem( SV_MENU_EDIT_SELECTALL, sal_False ); -// } - if ( !Edit::GetGetSpecialCharsFunction() ) - { - sal_uInt16 nPos = pPopup->GetItemPos( SV_MENU_EDIT_INSERTSYMBOL ); - pPopup->RemoveItem( nPos ); - pPopup->RemoveItem( nPos-1 ); - } - - mbActivePopup = sal_True; - Point aPos = rCEvt.GetMousePosPixel(); - if ( !rCEvt.IsMouseEvent() ) - { - // !!! Irgendwann einmal Menu zentriert in der Selektion anzeigen !!! - Size aSize = GetOutputSizePixel(); - aPos = Point( aSize.Width()/2, aSize.Height()/2 ); - } -// pPopup->RemoveDisabledEntries(); - sal_uInt16 n = pPopup->Execute( this, aPos ); - Edit::DeletePopupMenu( pPopup ); - switch ( n ) - { - case SV_MENU_EDIT_UNDO: mpExtTextView->Undo(); - mpExtTextEngine->SetModified( sal_True ); - mpExtTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) ); - break; - case SV_MENU_EDIT_CUT: mpExtTextView->Cut(); - mpExtTextEngine->SetModified( sal_True ); - mpExtTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) ); - break; - case SV_MENU_EDIT_COPY: mpExtTextView->Copy(); - break; - case SV_MENU_EDIT_PASTE: mpExtTextView->Paste(); - mpExtTextEngine->SetModified( sal_True ); - mpExtTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) ); - break; - case SV_MENU_EDIT_DELETE: mpExtTextView->DeleteSelected(); - mpExtTextEngine->SetModified( sal_True ); - mpExtTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) ); - break; - case SV_MENU_EDIT_SELECTALL: mpExtTextView->SetSelection( TextSelection( TextPaM( 0, 0 ), TextPaM( 0xFFFFFFFF, 0xFFFF ) ) ); - break; - case SV_MENU_EDIT_INSERTSYMBOL: - { - rtl::OUString aChars = Edit::GetGetSpecialCharsFunction()( this, GetFont() ); - if (!aChars.isEmpty()) - { - mpExtTextView->InsertText( aChars ); - mpExtTextEngine->SetModified( sal_True ); - mpExtTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) ); - } - } - break; - } - mbActivePopup = sal_False; - } - else - { - mpExtTextView->Command( rCEvt ); - } - Window::Command( rCEvt ); -} - -void TextWindow::GetFocus() -{ - Window::GetFocus(); - if ( !mbActivePopup ) - { - sal_Bool bGotoCursor = !mpExtTextView->IsReadOnly(); - if ( mbFocusSelectionHide && IsReallyVisible() && !mpExtTextView->IsReadOnly() - && ( mbSelectOnTab && - (!mbInMBDown || ( GetSettings().GetStyleSettings().GetSelectionOptions() & SELECTION_OPTION_FOCUS ) )) ) - { - // Alles selektieren, aber nicht scrollen - sal_Bool bAutoScroll = mpExtTextView->IsAutoScroll(); - mpExtTextView->SetAutoScroll( sal_False ); - mpExtTextView->SetSelection( TextSelection( TextPaM( 0, 0 ), TextPaM( 0xFFFF, 0xFFFF ) ) ); - mpExtTextView->SetAutoScroll( bAutoScroll ); - bGotoCursor = sal_False; - } - mpExtTextView->SetPaintSelection( sal_True ); - mpExtTextView->ShowCursor( bGotoCursor ); - } -} - -void TextWindow::LoseFocus() -{ - Window::LoseFocus(); +#include "unoiface.hxx" +#include - if ( mbFocusSelectionHide && !mbActivePopup ) - mpExtTextView->SetPaintSelection( sal_False ); -} -// virtual -::css::uno::Reference< ::css::awt::XWindowPeer > -TextWindow::GetComponentInterface(sal_Bool bCreate) -{ - ::css::uno::Reference< ::css::awt::XWindowPeer > xPeer( - Window::GetComponentInterface(false)); - if (!xPeer.is() && bCreate) - { - xPeer = new ::svt::TextWindowPeer(*GetTextView(), true); - SetComponentInterface(xPeer); - } - return xPeer; -} MultiLineEdit::MultiLineEdit( Window* pParent, WinBits nWinStyle ) - : Edit( pParent, nWinStyle ) + : VCLMultiLineEdit( pParent,nWinStyle ) { - SetType( WINDOW_MULTILINEEDIT ); - pImpSvMEdit = new ImpSvMEdit( this, nWinStyle ); - ImplInitSettings( sal_True, sal_True, sal_True ); - pUpdateDataTimer = 0; - - SetCompoundControl( sal_True ); - SetStyle( ImplInitStyle( nWinStyle ) ); } - MultiLineEdit::MultiLineEdit( Window* pParent, const ResId& rResId ) - : Edit( pParent, rResId.SetRT( RSC_MULTILINEEDIT ) ) -{ - SetType( WINDOW_MULTILINEEDIT ); - WinBits nWinStyle = rResId.GetWinBits(); - pImpSvMEdit = new ImpSvMEdit( this, nWinStyle ); - ImplInitSettings( sal_True, sal_True, sal_True ); - pUpdateDataTimer = 0; - - sal_uInt16 nMaxLen = Edit::GetMaxTextLen(); - if ( nMaxLen ) - SetMaxTextLen( nMaxLen ); - - SetText( Edit::GetText() ); - - if ( IsVisible() ) - pImpSvMEdit->Resize(); - - SetCompoundControl( sal_True ); - SetStyle( ImplInitStyle( nWinStyle ) ); - - // Base Edit ctor could call Show already, but that would cause problems - // with accessibility, as Show might (indirectly) trigger a call to virtual - // GetComponentInterface, which is the Edit's base version instead of the - // MultiLineEdit's version while in the base Edit ctor: - if ((GetStyle() & WB_HIDE) == 0) - Show(); - -} - -MultiLineEdit::~MultiLineEdit() -{ - { - ::std::auto_ptr< ImpSvMEdit > pDelete( pImpSvMEdit ); - pImpSvMEdit = NULL; - } - delete pUpdateDataTimer; -} - -WinBits MultiLineEdit::ImplInitStyle( WinBits nStyle ) -{ - if ( !(nStyle & WB_NOTABSTOP) ) - nStyle |= WB_TABSTOP; - - if ( !(nStyle & WB_NOGROUP) ) - nStyle |= WB_GROUP; - - if ( !(nStyle & WB_IGNORETAB )) - nStyle |= WINDOW_DLGCTRL_MOD1TAB; - - return nStyle; -} - - -void MultiLineEdit::ImplInitSettings( sal_Bool /*bFont*/, sal_Bool /*bForeground*/, sal_Bool bBackground ) -{ - const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); - - // Der Font muss immer mit manipuliert werden, weil die TextEngine - // sich nicht um TextColor/Background kuemmert - - Color aTextColor = rStyleSettings.GetFieldTextColor(); - if ( IsControlForeground() ) - aTextColor = GetControlForeground(); - if ( !IsEnabled() ) - aTextColor = rStyleSettings.GetDisableColor(); - - Font aFont = rStyleSettings.GetFieldFont(); - if ( IsControlFont() ) - aFont.Merge( GetControlFont() ); - aFont.SetTransparent( IsPaintTransparent() ); - SetZoomedPointFont( aFont ); - Font TheFont = GetFont(); - TheFont.SetColor( aTextColor ); - if( IsPaintTransparent() ) - TheFont.SetFillColor( Color( COL_TRANSPARENT ) ); - else - TheFont.SetFillColor( IsControlBackground() ? GetControlBackground() : rStyleSettings.GetFieldColor() ); - pImpSvMEdit->GetTextWindow()->SetFont( TheFont ); - pImpSvMEdit->GetTextWindow()->GetTextEngine()->SetFont( TheFont ); - pImpSvMEdit->GetTextWindow()->SetTextColor( aTextColor ); - - if ( bBackground ) - { - if( IsPaintTransparent() ) - { - pImpSvMEdit->GetTextWindow()->SetPaintTransparent( sal_True ); - pImpSvMEdit->GetTextWindow()->SetBackground(); - pImpSvMEdit->GetTextWindow()->SetControlBackground(); - SetBackground(); - SetControlBackground(); - } - else - { - if( IsControlBackground() ) - pImpSvMEdit->GetTextWindow()->SetBackground( GetControlBackground() ); - else - pImpSvMEdit->GetTextWindow()->SetBackground( rStyleSettings.GetFieldColor() ); - // Auch am MultiLineEdit einstellen, weil die TextComponent - // ggf. die Scrollbars hidet. - SetBackground( pImpSvMEdit->GetTextWindow()->GetBackground() ); - } - } -} - -void MultiLineEdit::Modify() -{ - aModifyHdlLink.Call( this ); - - CallEventListeners( VCLEVENT_EDIT_MODIFY ); - - if ( pUpdateDataTimer ) - pUpdateDataTimer->Start(); -} - -IMPL_LINK_NOARG(MultiLineEdit, ImpUpdateDataHdl) -{ - UpdateData(); - return 0; -} - -void MultiLineEdit::UpdateData() -{ - aUpdateDataHdlLink.Call( this ); -} - -void MultiLineEdit::SetModifyFlag() -{ - pImpSvMEdit->SetModified( sal_True ); -} - -void MultiLineEdit::ClearModifyFlag() -{ - pImpSvMEdit->SetModified( sal_False ); -} - -sal_Bool MultiLineEdit::IsModified() const -{ - return pImpSvMEdit->IsModified(); -} - -void MultiLineEdit::EnableUpdateData( sal_uLong nTimeout ) -{ - if ( !nTimeout ) - DisableUpdateData(); - else - { - if ( !pUpdateDataTimer ) - { - pUpdateDataTimer = new Timer; - pUpdateDataTimer->SetTimeoutHdl( LINK( this, MultiLineEdit, ImpUpdateDataHdl ) ); - } - pUpdateDataTimer->SetTimeout( nTimeout ); - } -} - -void MultiLineEdit::SetReadOnly( sal_Bool bReadOnly ) -{ - pImpSvMEdit->SetReadOnly( bReadOnly ); - Edit::SetReadOnly( bReadOnly ); - - // #94921# ReadOnly can be overwritten in InitFromStyle() when WB not set. - WinBits nStyle = GetStyle(); - if ( bReadOnly ) - nStyle |= WB_READONLY; - else - nStyle &= ~WB_READONLY; - SetStyle( nStyle ); -} - -sal_Bool MultiLineEdit::IsReadOnly() const -{ - return pImpSvMEdit->IsReadOnly(); -} - -void MultiLineEdit::SetMaxTextLen( xub_StrLen nMaxLen ) -{ - pImpSvMEdit->SetMaxTextLen( nMaxLen ); -} - -xub_StrLen MultiLineEdit::GetMaxTextLen() const -{ - return pImpSvMEdit->GetMaxTextLen(); -} - -void MultiLineEdit::ReplaceSelected( const String& rStr ) -{ - pImpSvMEdit->InsertText( rStr ); -} - -void MultiLineEdit::DeleteSelected() -{ - pImpSvMEdit->InsertText( String() ); -} - -String MultiLineEdit::GetSelected() const -{ - return pImpSvMEdit->GetSelected(); -} - -String MultiLineEdit::GetSelected( LineEnd aSeparator ) const -{ - return pImpSvMEdit->GetSelected( aSeparator ); -} - -void MultiLineEdit::Cut() -{ - pImpSvMEdit->Cut(); -} - -void MultiLineEdit::Copy() -{ - pImpSvMEdit->Copy(); -} - -void MultiLineEdit::Paste() -{ - pImpSvMEdit->Paste(); -} - -void MultiLineEdit::SetText( const String& rStr ) -{ - pImpSvMEdit->SetText( rStr ); -} - -String MultiLineEdit::GetText() const -{ - return pImpSvMEdit->GetText(); -} - -String MultiLineEdit::GetText( LineEnd aSeparator ) const -{ - return pImpSvMEdit->GetText( aSeparator ); -} - -String MultiLineEdit::GetTextLines( LineEnd aSeparator ) const -{ - return pImpSvMEdit->GetTextLines( aSeparator ); -} - -void MultiLineEdit::Resize() -{ - pImpSvMEdit->Resize(); -} - -void MultiLineEdit::GetFocus() -{ - if ( !pImpSvMEdit ) // might be called from within the dtor, when pImpSvMEdit == NULL is a valid state - return; - - Edit::GetFocus(); - pImpSvMEdit->GetFocus(); -} - -void MultiLineEdit::SetSelection( const Selection& rSelection ) -{ - pImpSvMEdit->SetSelection( rSelection ); -} - -const Selection& MultiLineEdit::GetSelection() const -{ - return pImpSvMEdit->GetSelection(); -} - -Size MultiLineEdit::CalcMinimumSize() const -{ - Size aSz = pImpSvMEdit->CalcMinimumSize(); - - sal_Int32 nLeft, nTop, nRight, nBottom; - ((Window*)this)->GetBorder( nLeft, nTop, nRight, nBottom ); - aSz.Width() += nLeft+nRight; - aSz.Height() += nTop+nBottom; - - return aSz; -} - -Size MultiLineEdit::CalcAdjustedSize( const Size& rPrefSize ) const -{ - Size aSz = rPrefSize; - sal_Int32 nLeft, nTop, nRight, nBottom; - ((Window*)this)->GetBorder( nLeft, nTop, nRight, nBottom ); - - // In der Hoehe auf ganze Zeilen justieren - - long nHeight = aSz.Height() - nTop - nBottom; - long nLineHeight = pImpSvMEdit->CalcSize( 1, 1 ).Height(); - long nLines = nHeight / nLineHeight; - if ( nLines < 1 ) - nLines = 1; - - aSz.Height() = nLines * nLineHeight; - aSz.Height() += nTop+nBottom; - - return aSz; -} - -Size MultiLineEdit::CalcSize( sal_uInt16 nColumns, sal_uInt16 nLines ) const -{ - Size aSz = pImpSvMEdit->CalcSize( nColumns, nLines ); - - sal_Int32 nLeft, nTop, nRight, nBottom; - ((Window*)this)->GetBorder( nLeft, nTop, nRight, nBottom ); - aSz.Width() += nLeft+nRight; - aSz.Height() += nTop+nBottom; - return aSz; -} - -void MultiLineEdit::GetMaxVisColumnsAndLines( sal_uInt16& rnCols, sal_uInt16& rnLines ) const -{ - pImpSvMEdit->GetMaxVisColumnsAndLines( rnCols, rnLines ); -} - -void MultiLineEdit::StateChanged( StateChangedType nType ) -{ - if( nType == STATE_CHANGE_ENABLE ) - { - pImpSvMEdit->Enable( IsEnabled() ); - ImplInitSettings( sal_True, sal_False, sal_False ); - } - else if( nType == STATE_CHANGE_READONLY ) - { - pImpSvMEdit->SetReadOnly( IsReadOnly() ); - } - else if ( nType == STATE_CHANGE_ZOOM ) - { - pImpSvMEdit->GetTextWindow()->SetZoom( GetZoom() ); - ImplInitSettings( sal_True, sal_False, sal_False ); - Resize(); - } - else if ( nType == STATE_CHANGE_CONTROLFONT ) - { - ImplInitSettings( sal_True, sal_False, sal_False ); - Resize(); - Invalidate(); - } - else if ( nType == STATE_CHANGE_CONTROLFOREGROUND ) - { - ImplInitSettings( sal_False, sal_True, sal_False ); - Invalidate(); - } - else if ( nType == STATE_CHANGE_CONTROLBACKGROUND ) - { - ImplInitSettings( sal_False, sal_False, sal_True ); - Invalidate(); - } - else if ( nType == STATE_CHANGE_STYLE ) - { - pImpSvMEdit->InitFromStyle( GetStyle() ); - SetStyle( ImplInitStyle( GetStyle() ) ); - } - else if ( nType == STATE_CHANGE_INITSHOW ) - { - if( IsPaintTransparent() ) - { - pImpSvMEdit->GetTextWindow()->SetPaintTransparent( sal_True ); - pImpSvMEdit->GetTextWindow()->SetBackground(); - pImpSvMEdit->GetTextWindow()->SetControlBackground(); - SetBackground(); - SetControlBackground(); - } - } - - Control::StateChanged( nType ); -} - -void MultiLineEdit::DataChanged( const DataChangedEvent& rDCEvt ) -{ - if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && - (rDCEvt.GetFlags() & SETTINGS_STYLE) ) - { - ImplInitSettings( sal_True, sal_True, sal_True ); - Resize(); - Invalidate(); - } - else - Control::DataChanged( rDCEvt ); -} - -void MultiLineEdit::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, sal_uLong nFlags ) -{ - ImplInitSettings( sal_True, sal_True, sal_True ); - - Point aPos = pDev->LogicToPixel( rPos ); - Size aSize = pDev->LogicToPixel( rSize ); - Font aFont = pImpSvMEdit->GetTextWindow()->GetDrawPixelFont( pDev ); - aFont.SetTransparent( sal_True ); - OutDevType eOutDevType = pDev->GetOutDevType(); - - pDev->Push(); - pDev->SetMapMode(); - pDev->SetFont( aFont ); - pDev->SetTextFillColor(); - - // Border/Background - pDev->SetLineColor(); - pDev->SetFillColor(); - sal_Bool bBorder = !(nFlags & WINDOW_DRAW_NOBORDER ) && (GetStyle() & WB_BORDER); - sal_Bool bBackground = !(nFlags & WINDOW_DRAW_NOBACKGROUND) && IsControlBackground(); - if ( bBorder || bBackground ) - { - Rectangle aRect( aPos, aSize ); - if ( bBorder ) - { - DecorationView aDecoView( pDev ); - aRect = aDecoView.DrawFrame( aRect, FRAME_DRAW_DOUBLEIN ); - } - if ( bBackground ) - { - pDev->SetFillColor( GetControlBackground() ); - pDev->DrawRect( aRect ); - } - } - - // Inhalt - if ( ( nFlags & WINDOW_DRAW_MONO ) || ( eOutDevType == OUTDEV_PRINTER ) ) - pDev->SetTextColor( Color( COL_BLACK ) ); - else - { - if ( !(nFlags & WINDOW_DRAW_NODISABLE ) && !IsEnabled() ) - { - const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); - pDev->SetTextColor( rStyleSettings.GetDisableColor() ); - } - else - { - pDev->SetTextColor( GetTextColor() ); - } - } - - rtl::OUString aText = GetText(); - Size aTextSz( pDev->GetTextWidth( aText ), pDev->GetTextHeight() ); - sal_uLong nLines = (sal_uLong) (aSize.Height() / aTextSz.Height()); - if ( !nLines ) - nLines = 1; - aTextSz.Height() = nLines*aTextSz.Height(); - long nOnePixel = GetDrawPixel( pDev, 1 ); - long nOffX = 3*nOnePixel; - long nOffY = 2*nOnePixel; - - // Clipping? - if ( ( nOffY < 0 ) || ( (nOffY+aTextSz.Height()) > aSize.Height() ) || ( (nOffX+aTextSz.Width()) > aSize.Width() ) ) - { - Rectangle aClip( aPos, aSize ); - if ( aTextSz.Height() > aSize.Height() ) - aClip.Bottom() += aTextSz.Height() - aSize.Height() + 1; // Damit HP-Drucker nicht 'weg-optimieren' - pDev->IntersectClipRegion( aClip ); - } - - TextEngine aTE; - aTE.SetText( GetText() ); - aTE.SetMaxTextWidth( aSize.Width() ); - aTE.SetFont( aFont ); - aTE.SetTextAlign( pImpSvMEdit->GetTextWindow()->GetTextEngine()->GetTextAlign() ); - aTE.Draw( pDev, Point( aPos.X() + nOffX, aPos.Y() + nOffY ) ); - - pDev->Pop(); -} - -long MultiLineEdit::Notify( NotifyEvent& rNEvt ) -{ - long nDone = 0; - if( rNEvt.GetType() == EVENT_COMMAND ) - { - nDone = pImpSvMEdit->HandleCommand( *rNEvt.GetCommandEvent() ); - } - return nDone ? nDone : Edit::Notify( rNEvt ); -} - -long MultiLineEdit::PreNotify( NotifyEvent& rNEvt ) -{ - long nDone = 0; - -#if (OSL_DEBUG_LEVEL > 1) && defined(DBG_UTIL) - if( rNEvt.GetType() == EVENT_KEYINPUT ) - { - const KeyEvent& rKEvent = *rNEvt.GetKeyEvent(); - if ( ( rKEvent.GetKeyCode().GetCode() == KEY_W ) && rKEvent.GetKeyCode().IsMod1() && rKEvent.GetKeyCode().IsMod2() ) - { - SetRightToLeft( !IsRightToLeft() ); - } - } -#endif - - if( ( rNEvt.GetType() == EVENT_KEYINPUT ) && ( !GetTextView()->IsCursorEnabled() ) ) - { - const KeyEvent& rKEvent = *rNEvt.GetKeyEvent(); - if ( !rKEvent.GetKeyCode().IsShift() && ( rKEvent.GetKeyCode().GetGroup() == KEYGROUP_CURSOR ) ) - { - nDone = 1; - TextSelection aSel = pImpSvMEdit->GetTextWindow()->GetTextView()->GetSelection(); - if ( aSel.HasRange() ) - { - aSel.GetStart() = aSel.GetEnd(); - pImpSvMEdit->GetTextWindow()->GetTextView()->SetSelection( aSel ); - } - else - { - switch ( rKEvent.GetKeyCode().GetCode() ) - { - case KEY_UP: - { - if ( pImpSvMEdit->GetVScrollBar() ) - pImpSvMEdit->GetVScrollBar()->DoScrollAction( SCROLL_LINEUP ); - } - break; - case KEY_DOWN: - { - if ( pImpSvMEdit->GetVScrollBar() ) - pImpSvMEdit->GetVScrollBar()->DoScrollAction( SCROLL_LINEDOWN ); - } - break; - case KEY_PAGEUP : - { - if ( pImpSvMEdit->GetVScrollBar() ) - pImpSvMEdit->GetVScrollBar()->DoScrollAction( SCROLL_PAGEUP ); - } - break; - case KEY_PAGEDOWN: - { - if ( pImpSvMEdit->GetVScrollBar() ) - pImpSvMEdit->GetVScrollBar()->DoScrollAction( SCROLL_PAGEDOWN ); - } - break; - case KEY_LEFT: - { - if ( pImpSvMEdit->GetHScrollBar() ) - pImpSvMEdit->GetHScrollBar()->DoScrollAction( SCROLL_LINEUP ); - } - break; - case KEY_RIGHT: - { - if ( pImpSvMEdit->GetHScrollBar() ) - pImpSvMEdit->GetHScrollBar()->DoScrollAction( SCROLL_LINEDOWN ); - } - break; - case KEY_HOME: - { - if ( rKEvent.GetKeyCode().IsMod1() ) - pImpSvMEdit->GetTextWindow()->GetTextView()-> - SetSelection( TextSelection( TextPaM( 0, 0 ) ) ); - } - break; - case KEY_END: - { - if ( rKEvent.GetKeyCode().IsMod1() ) - pImpSvMEdit->GetTextWindow()->GetTextView()-> - SetSelection( TextSelection( TextPaM( 0xFFFF, 0xFFFF ) ) ); - } - break; - default: - { - nDone = 0; - } - } - } - } - } - - return nDone ? nDone : Edit::PreNotify( rNEvt ); -} - -// -// Internas fuer abgeleitete Klassen, z.B. TextComponent - -ExtTextEngine* MultiLineEdit::GetTextEngine() const -{ - return pImpSvMEdit->GetTextWindow()->GetTextEngine(); -} - -ExtTextView* MultiLineEdit::GetTextView() const -{ - return pImpSvMEdit->GetTextWindow()->GetTextView(); -} - -ScrollBar* MultiLineEdit::GetVScrollBar() const -{ - return pImpSvMEdit->GetVScrollBar(); -} - -void MultiLineEdit::EnableFocusSelectionHide( sal_Bool bHide ) -{ - pImpSvMEdit->GetTextWindow()->SetAutoFocusHide( bHide ); -} - -void MultiLineEdit::SetLeftMargin( sal_uInt16 n ) + : VCLMultiLineEdit( pParent,rResId ) { - if ( GetTextEngine() ) - GetTextEngine()->SetLeftMargin( n ); } -void MultiLineEdit::SetRightToLeft( sal_Bool bRightToLeft ) -{ - if ( GetTextEngine() ) - { - GetTextEngine()->SetRightToLeft( bRightToLeft ); - GetTextView()->ShowCursor(); - } -} - -sal_Bool MultiLineEdit::IsRightToLeft() const -{ - sal_Bool bRightToLeft = sal_False; - - if ( GetTextEngine() ) - bRightToLeft = GetTextEngine()->IsRightToLeft(); - - return bRightToLeft; -} +namespace css = ::com::sun::star; // virtual ::css::uno::Reference< ::css::awt::XWindowPeer > MultiLineEdit::GetComponentInterface(sal_Bool bCreate) { ::css::uno::Reference< ::css::awt::XWindowPeer > xPeer( - Edit::GetComponentInterface(false)); + VCLMultiLineEdit::GetComponentInterface(false)); if (!xPeer.is() && bCreate) { - ::std::auto_ptr< VCLXMultiLineEdit > xEdit(new VCLXMultiLineEdit()); - xEdit->SetWindow(this); - xPeer = xEdit.release(); + ::std::auto_ptr< VCLXMultiLineEdit > xVCLMEdit(new VCLXMultiLineEdit()); + xVCLMEdit->SetWindow(this); + xPeer = xVCLMEdit.release(); SetComponentInterface(xPeer); } return xPeer; } -void MultiLineEdit::DisableSelectionOnFocus() -{ - pImpSvMEdit->GetTextWindow()->DisableSelectionOnFocus(); -} - -void MultiLineEdit::SetTextSelectable( sal_Bool bTextSelectable ) -{ - pImpSvMEdit->GetTextWindow()->SetTextSelectable( bTextSelectable ); -} - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svtools/source/edit/svmedit2.cxx b/svtools/source/edit/svmedit2.cxx index abd2fcf..8d530b2 100644 --- a/svtools/source/edit/svmedit2.cxx +++ b/svtools/source/edit/svmedit2.cxx @@ -19,7 +19,7 @@ #include -#include +#include ExtMultiLineEdit::ExtMultiLineEdit( Window* pParent, WinBits nWinStyle ) : diff --git a/svtools/source/edit/textdat2.hxx b/svtools/source/edit/textdat2.hxx deleted file mode 100644 index c52d33e..0000000 --- a/svtools/source/edit/textdat2.hxx +++ /dev/null @@ -1,312 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2000, 2010 Oracle and/or its affiliates. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * - * for a copy of the LGPLv3 License. - * - ************************************************************************/ - - -#ifndef _TEXTDAT2_HXX -#define _TEXTDAT2_HXX - -#include -#include -#include - -#include - -class TextNode; -class TextView; - -#define PORTIONKIND_TEXT 0 -#define PORTIONKIND_TAB 1 - -#define DELMODE_SIMPLE 0 -#define DELMODE_RESTOFWORD 1 -#define DELMODE_RESTOFCONTENT 2 - -#define DEL_LEFT 1 -#define DEL_RIGHT 2 -#define TRAVEL_X_DONTKNOW 0xFFFF -#define MAXCHARSINPARA 0x3FFF-CHARPOSGROW - -#define LINE_SEP 0x0A - - -class TETextPortion -{ -private: - sal_uInt16 nLen; - long nWidth; - sal_uInt8 nKind; - sal_uInt8 nRightToLeft; - - TETextPortion() { nLen = 0; nKind = PORTIONKIND_TEXT; nWidth = -1; nRightToLeft = 0;} - -public: - TETextPortion( sal_uInt16 nL ) { - nLen = nL; - nKind = PORTIONKIND_TEXT; - nWidth= -1; - nRightToLeft = 0; - } - - sal_uInt16 GetLen() const { return nLen; } - sal_uInt16& GetLen() { return nLen; } - - long GetWidth()const { return nWidth; } - long& GetWidth() { return nWidth; } - - sal_uInt8 GetKind() const { return nKind; } - sal_uInt8& GetKind() { return nKind; } - - sal_uInt8 GetRightToLeft() const { return nRightToLeft; } - sal_uInt8& GetRightToLeft() { return nRightToLeft; } - sal_Bool IsRightToLeft() const { return (nRightToLeft&1); } - - sal_Bool HasValidSize() const { return nWidth != (-1); } -}; - - - -typedef std::vector TextPortionArray; - -class TETextPortionList : public TextPortionArray -{ -public: - TETextPortionList(); - ~TETextPortionList(); - - void Reset(); - sal_uInt16 FindPortion( sal_uInt16 nCharPos, sal_uInt16& rPortionStart, sal_Bool bPreferStartingPortion = sal_False ); - sal_uInt16 GetPortionStartIndex( sal_uInt16 nPortion ); - void DeleteFromPortion( sal_uInt16 nDelFrom ); -}; - -struct TEWritingDirectionInfo -{ - sal_uInt8 nType; - sal_uInt16 nStartPos; - sal_uInt16 nEndPos; - TEWritingDirectionInfo( sal_uInt8 _Type, sal_uInt16 _Start, sal_uInt16 _End ) - { - nType = _Type; - nStartPos = _Start; - nEndPos = _End; - } -}; - -class TextLine -{ -private: - sal_uInt16 mnStart; - sal_uInt16 mnEnd; - sal_uInt16 mnStartPortion; - sal_uInt16 mnEndPortion; - - short mnStartX; - - sal_Bool mbInvalid; // fuer geschickte Formatierung/Ausgabe - -public: - TextLine() { - mnStart = mnEnd = 0; - mnStartPortion = mnEndPortion = 0; - mnStartX = 0; - mbInvalid = sal_True; - } - - sal_Bool IsIn( sal_uInt16 nIndex ) const - { return ( (nIndex >= mnStart ) && ( nIndex < mnEnd ) ); } - - sal_Bool IsIn( sal_uInt16 nIndex, sal_Bool bInclEnd ) const - { return ( ( nIndex >= mnStart ) && ( bInclEnd ? ( nIndex <= mnEnd ) : ( nIndex < mnEnd ) ) ); } - - void SetStart( sal_uInt16 n ) { mnStart = n; } - sal_uInt16 GetStart() const { return mnStart; } - sal_uInt16& GetStart() { return mnStart; } - - void SetEnd( sal_uInt16 n ) { mnEnd = n; } - sal_uInt16 GetEnd() const { return mnEnd; } - sal_uInt16& GetEnd() { return mnEnd; } - - void SetStartPortion( sal_uInt16 n ) { mnStartPortion = n; } - sal_uInt16 GetStartPortion() const { return mnStartPortion; } - sal_uInt16& GetStartPortion() { return mnStartPortion; } - - void SetEndPortion( sal_uInt16 n ) { mnEndPortion = n; } - sal_uInt16 GetEndPortion() const { return mnEndPortion; } - sal_uInt16& GetEndPortion() { return mnEndPortion; } - - sal_uInt16 GetLen() const { return mnEnd - mnStart; } - - sal_Bool IsInvalid() const { return mbInvalid; } - sal_Bool IsValid() const { return !mbInvalid; } - void SetInvalid() { mbInvalid = sal_True; } - void SetValid() { mbInvalid = sal_False; } - - sal_Bool IsEmpty() const { return (mnEnd > mnStart) ? sal_False : sal_True; } - - short GetStartX() const { return mnStartX; } - void SetStartX( short n ) { mnStartX = n; } - - inline sal_Bool operator == ( const TextLine& rLine ) const; - inline sal_Bool operator != ( const TextLine& rLine ) const; -}; - -class TextLines : public std::vector { -public: - ~TextLines() - { - for( iterator it = begin(); it != end(); ++it ) - delete *it; - } -}; - -inline sal_Bool TextLine::operator == ( const TextLine& rLine ) const -{ - return ( ( mnStart == rLine.mnStart ) && - ( mnEnd == rLine.mnEnd ) && - ( mnStartPortion == rLine.mnStartPortion ) && - ( mnEndPortion == rLine.mnEndPortion ) ); -} - -inline sal_Bool TextLine::operator != ( const TextLine& rLine ) const -{ - return !( *this == rLine ); -} - - - -class TEParaPortion -{ -private: - TextNode* mpNode; - - TextLines maLines; - TETextPortionList maTextPortions; - std::vector maWritingDirectionInfos; - - - sal_uInt16 mnInvalidPosStart; - short mnInvalidDiff; - - sal_Bool mbInvalid; - sal_Bool mbSimple; // nur lineares Tippen - - - TEParaPortion( const TEParaPortion& ) {;} - -public: - TEParaPortion( TextNode* pNode ); - ~TEParaPortion(); - - - sal_Bool IsInvalid() const { return mbInvalid; } - sal_Bool IsSimpleInvalid() const { return mbSimple; } - void SetNotSimpleInvalid() { mbSimple = sal_False; } - void SetValid() { mbInvalid = sal_False; mbSimple = sal_True;} - - void MarkInvalid( sal_uInt16 nStart, short nDiff); - void MarkSelectionInvalid( sal_uInt16 nStart, sal_uInt16 nEnd ); - - sal_uInt16 GetInvalidPosStart() const { return mnInvalidPosStart; } - short GetInvalidDiff() const { return mnInvalidDiff; } - - TextNode* GetNode() const { return mpNode; } - TextLines& GetLines() { return maLines; } - TETextPortionList& GetTextPortions() { return maTextPortions; } - std::vector& GetWritingDirectionInfos() { return maWritingDirectionInfos; } - - - sal_uInt16 GetLineNumber( sal_uInt16 nIndex, sal_Bool bInclEnd ); - void CorrectValuesBehindLastFormattedLine( sal_uInt16 nLastFormattedLine ); -}; - - -class TEParaPortions : public ToolsList -{ -public: - TEParaPortions(); - ~TEParaPortions(); - void Reset(); -}; - - -class TextSelFunctionSet: public FunctionSet -{ -private: - TextView* mpView; - -public: - TextSelFunctionSet( TextView* pView ); - - virtual void BeginDrag(); - - virtual void CreateAnchor(); - - virtual sal_Bool SetCursorAtPoint( const Point& rPointPixel, sal_Bool bDontSelectAtCursor = sal_False ); - - virtual sal_Bool IsSelectionAtPoint( const Point& rPointPixel ); - virtual void DeselectAll(); - - virtual void DeselectAtPoint( const Point& ); - virtual void DestroyAnchor(); -}; - - -class IdleFormatter : public Timer -{ -private: - TextView* mpView; - sal_uInt16 mnRestarts; - -public: - IdleFormatter(); - ~IdleFormatter(); - - void DoIdleFormat( TextView* pV, sal_uInt16 nMaxRestarts ); - void ForceTimeout(); - TextView* GetView() { return mpView; } -}; - -struct TextDDInfo -{ - Cursor maCursor; - TextPaM maDropPos; - - sal_Bool mbStarterOfDD; - sal_Bool mbVisCursor; - - TextDDInfo() - { - maCursor.SetStyle( CURSOR_SHADOW ); - mbStarterOfDD = sal_False; - mbVisCursor = sal_False; - } -}; - -#endif // _TEXTDAT2_HXX - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svtools/source/edit/textdata.cxx b/svtools/source/edit/textdata.cxx deleted file mode 100644 index 7d55ee1..0000000 --- a/svtools/source/edit/textdata.cxx +++ /dev/null @@ -1,345 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2000, 2010 Oracle and/or its affiliates. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * - * for a copy of the LGPLv3 License. - * - ************************************************************************/ - - -#include -#include - -#include - - -// ------------------------------------------------------------------------- -// (+) class TextSelection -// ------------------------------------------------------------------------- - -TextSelection::TextSelection() -{ -} - -TextSelection::TextSelection( const TextPaM& rPaM ) : - maStartPaM( rPaM ), maEndPaM( rPaM ) -{ -} - -TextSelection::TextSelection( const TextPaM& rStart, const TextPaM& rEnd ) : - maStartPaM( rStart ), maEndPaM( rEnd ) -{ -} - -void TextSelection::Justify() -{ - if ( maEndPaM < maStartPaM ) - { - TextPaM aTemp( maStartPaM ); - maStartPaM = maEndPaM; - maEndPaM = aTemp; - } -} - - -// ------------------------------------------------------------------------- -// (+) class TETextPortionList -// ------------------------------------------------------------------------- -TETextPortionList::TETextPortionList() -{ -} - -TETextPortionList::~TETextPortionList() -{ - Reset(); -} - -void TETextPortionList::Reset() -{ - for ( iterator it = begin(); it != end(); ++it ) - delete *it; - clear(); -} - -void TETextPortionList::DeleteFromPortion( sal_uInt16 nDelFrom ) -{ - DBG_ASSERT( ( nDelFrom < size() ) || ( (nDelFrom == 0) && (size() == 0) ), "DeleteFromPortion: Out of range" ); - for ( iterator it = begin() + nDelFrom; it != end(); ++it ) - delete *it; - erase( begin() + nDelFrom, end() ); -} - -sal_uInt16 TETextPortionList::FindPortion( sal_uInt16 nCharPos, sal_uInt16& nPortionStart, sal_Bool bPreferStartingPortion ) -{ - // Bei nCharPos an Portion-Grenze wird die linke Portion gefunden - sal_uInt16 nTmpPos = 0; - for ( sal_uInt16 nPortion = 0; nPortion < size(); nPortion++ ) - { - TETextPortion* pPortion = operator[]( nPortion ); - nTmpPos = nTmpPos + pPortion->GetLen(); - if ( nTmpPos >= nCharPos ) - { - // take this one if we don't prefer the starting portion, or if it's the last one - if ( ( nTmpPos != nCharPos ) || !bPreferStartingPortion || ( nPortion == size() - 1 ) ) - { - nPortionStart = nTmpPos - pPortion->GetLen(); - return nPortion; - } - } - } - OSL_FAIL( "FindPortion: Nicht gefunden!" ); - return ( size() - 1 ); -} - - -// ------------------------------------------------------------------------- -// (+) class TEParaPortion -// ------------------------------------------------------------------------- -TEParaPortion::TEParaPortion( TextNode* pN ) -{ - mpNode = pN; - mnInvalidPosStart = mnInvalidDiff = 0; - mbInvalid = sal_True; - mbSimple = sal_False; -} - -TEParaPortion::~TEParaPortion() -{ -} - -void TEParaPortion::MarkInvalid( sal_uInt16 nStart, short nDiff ) -{ - if ( mbInvalid == sal_False ) - { - mnInvalidPosStart = ( nDiff >= 0 ) ? nStart : ( nStart + nDiff ); - mnInvalidDiff = nDiff; - } - else - { - // Einfaches hintereinander tippen - if ( ( nDiff > 0 ) && ( mnInvalidDiff > 0 ) && - ( ( mnInvalidPosStart+mnInvalidDiff ) == nStart ) ) - { - mnInvalidDiff = mnInvalidDiff + nDiff; - } - // Einfaches hintereinander loeschen - else if ( ( nDiff < 0 ) && ( mnInvalidDiff < 0 ) && ( mnInvalidPosStart == nStart ) ) - { - mnInvalidPosStart = mnInvalidPosStart + nDiff; - mnInvalidDiff = mnInvalidDiff + nDiff; - } - else - { - DBG_ASSERT( ( nDiff >= 0 ) || ( (nStart+nDiff) >= 0 ), "MarkInvalid: Diff out of Range" ); - mnInvalidPosStart = Min( mnInvalidPosStart, (sal_uInt16) ( (nDiff < 0) ? nStart+nDiff : nDiff ) ); - mnInvalidDiff = 0; - mbSimple = sal_False; - } - } - - maWritingDirectionInfos.clear(); - - mbInvalid = sal_True; -} - -void TEParaPortion::MarkSelectionInvalid( sal_uInt16 nStart, sal_uInt16 /*nEnd*/ ) -{ - if ( mbInvalid == sal_False ) - { - mnInvalidPosStart = nStart; -// nInvalidPosEnd = nEnd; - } - else - { - mnInvalidPosStart = Min( mnInvalidPosStart, nStart ); -// nInvalidPosEnd = pNode->Len(); - } - - maWritingDirectionInfos.clear(); - - mnInvalidDiff = 0; - mbInvalid = sal_True; - mbSimple = sal_False; -} - -sal_uInt16 TEParaPortion::GetLineNumber( sal_uInt16 nChar, sal_Bool bInclEnd ) -{ - for ( sal_uInt16 nLine = 0; nLine < maLines.size(); nLine++ ) - { - TextLine* pLine = maLines[ nLine ]; - if ( ( bInclEnd && ( pLine->GetEnd() >= nChar ) ) || - ( pLine->GetEnd() > nChar ) ) - { - return nLine; - } - } - - // Then it should be at the end of the last line - OSL_ENSURE(nChar == maLines[maLines.size() - 1]->GetEnd(), "wrong Index"); - OSL_ENSURE(!bInclEnd, "Line not found: FindLine"); - return ( maLines.size() - 1 ); -} - - -void TEParaPortion::CorrectValuesBehindLastFormattedLine( sal_uInt16 nLastFormattedLine ) -{ - sal_uInt16 nLines = maLines.size(); - DBG_ASSERT( nLines, "CorrectPortionNumbersFromLine: Leere Portion?" ); - if ( nLastFormattedLine < ( nLines - 1 ) ) - { - const TextLine* pLastFormatted = maLines[ nLastFormattedLine ]; - const TextLine* pUnformatted = maLines[ nLastFormattedLine+1 ]; - short nPortionDiff = pUnformatted->GetStartPortion() - pLastFormatted->GetEndPortion(); - short nTextDiff = pUnformatted->GetStart() - pLastFormatted->GetEnd(); - nTextDiff++; // LastFormatted->GetEnd() war incl. => 1 zuviel abgezogen! - - // Die erste unformatierte muss genau eine Portion hinter der letzten der - // formatierten beginnen: - // Wenn in der geaenderten Zeile eine Portion gesplittet wurde, - // kann nLastEnd > nNextStart sein! - short nPDiff = sal::static_int_cast< short >(-( nPortionDiff-1 )); - short nTDiff = sal::static_int_cast< short >(-( nTextDiff-1 )); - if ( nPDiff || nTDiff ) - { - for ( sal_uInt16 nL = nLastFormattedLine+1; nL < nLines; nL++ ) - { - TextLine* pLine = maLines[ nL ]; - - pLine->GetStartPortion() = pLine->GetStartPortion() + nPDiff; - pLine->GetEndPortion() = pLine->GetEndPortion() + nPDiff; - - pLine->GetStart() = pLine->GetStart() + nTDiff; - pLine->GetEnd() = pLine->GetEnd() + nTDiff; - - pLine->SetValid(); - } - } - } -} - -// ------------------------------------------------------------------------- -// (+) class TEParaPortions -// ------------------------------------------------------------------------- -TEParaPortions::TEParaPortions() -{ -} - -TEParaPortions::~TEParaPortions() -{ - Reset(); -} - -void TEParaPortions::Reset() -{ - TEParaPortions::iterator aIter( begin() ); - while ( aIter != end() ) - delete *aIter++; - clear(); -} - -// ------------------------------------------------------------------------- -// (+) class IdleFormatter -// ------------------------------------------------------------------------- -IdleFormatter::IdleFormatter() -{ - mpView = 0; - mnRestarts = 0; -} - -IdleFormatter::~IdleFormatter() -{ - mpView = 0; -} - -void IdleFormatter::DoIdleFormat( TextView* pV, sal_uInt16 nMaxRestarts ) -{ - mpView = pV; - - if ( IsActive() ) - mnRestarts++; - - if ( mnRestarts > nMaxRestarts ) - { - mnRestarts = 0; - ((Link&)GetTimeoutHdl()).Call( this ); - } - else - { - Start(); - } -} - -void IdleFormatter::ForceTimeout() -{ - if ( IsActive() ) - { - Stop(); - mnRestarts = 0; - ((Link&)GetTimeoutHdl()).Call( this ); - } -} - -TYPEINIT1( TextHint, SfxSimpleHint ); - -TextHint::TextHint( sal_uLong Id ) : SfxSimpleHint( Id ) -{ - mnValue = 0; -} - -TextHint::TextHint( sal_uLong Id, sal_uLong nValue ) : SfxSimpleHint( Id ) -{ - mnValue = nValue; -} - -TEIMEInfos::TEIMEInfos( const TextPaM& rPos, const String& rOldTextAfterStartPos ) -: aOldTextAfterStartPos( rOldTextAfterStartPos ) -{ - aPos = rPos; - nLen = 0; - bCursor = sal_True; - pAttribs = NULL; - bWasCursorOverwrite = sal_False; -} - -TEIMEInfos::~TEIMEInfos() -{ - delete[] pAttribs; -} - -void TEIMEInfos::CopyAttribs( const sal_uInt16* pA, sal_uInt16 nL ) -{ - nLen = nL; - delete pAttribs; - pAttribs = new sal_uInt16[ nL ]; - memcpy( pAttribs, pA, nL*sizeof(sal_uInt16) ); -} - -void TEIMEInfos::DestroyAttribs() -{ - delete pAttribs; - pAttribs = NULL; - nLen = 0; -} - - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svtools/source/edit/textdoc.cxx b/svtools/source/edit/textdoc.cxx deleted file mode 100644 index a8062ec..0000000 --- a/svtools/source/edit/textdoc.cxx +++ /dev/null @@ -1,636 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2000, 2010 Oracle and/or its affiliates. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * - * for a copy of the LGPLv3 License. - * - ************************************************************************/ - -#include - -#include - - - -// Vergleichmethode wird von QuickSort gerufen... - -static bool CompareStart( const TextCharAttrib* pFirst, const TextCharAttrib* pSecond ) -{ - return pFirst->GetStart() < pSecond->GetStart(); -} - -// ------------------------------------------------------------------------- -// (+) class TextCharAttrib -// ------------------------------------------------------------------------- -TextCharAttrib::TextCharAttrib( const TextAttrib& rAttr, sal_uInt16 nStart, sal_uInt16 nEnd ) -{ - mpAttr = rAttr.Clone(); - mnStart = nStart, - mnEnd = nEnd; -} - -TextCharAttrib::TextCharAttrib( const TextCharAttrib& rTextCharAttrib ) -{ - mpAttr = rTextCharAttrib.GetAttr().Clone(); - mnStart = rTextCharAttrib.mnStart; - mnEnd = rTextCharAttrib.mnEnd; -} - -TextCharAttrib::~TextCharAttrib() -{ - delete mpAttr; -} - -// ------------------------------------------------------------------------- -// (+) class TextCharAttribList -// ------------------------------------------------------------------------- - -TextCharAttribList::TextCharAttribList() -{ - mbHasEmptyAttribs = sal_False; -} - -TextCharAttribList::~TextCharAttribList() -{ - // PTRARR_DEL -} - -void TextCharAttribList::Clear( sal_Bool bDestroyAttribs ) -{ - if ( bDestroyAttribs ) - for(iterator it = begin(); it != end(); ++it) - delete *it; - TextCharAttribs::clear(); -} - - -void TextCharAttribList::InsertAttrib( TextCharAttrib* pAttrib ) -{ - if ( pAttrib->IsEmpty() ) - mbHasEmptyAttribs = sal_True; - - const sal_uInt16 nCount = size(); - const sal_uInt16 nStart = pAttrib->GetStart(); // vielleicht besser fuer Comp.Opt. - sal_Bool bInserted = sal_False; - for ( sal_uInt16 x = 0; x < nCount; x++ ) - { - TextCharAttrib* pCurAttrib = GetAttrib( x ); - if ( pCurAttrib->GetStart() > nStart ) - { - insert( begin() + x, pAttrib ); - bInserted = sal_True; - break; - } - } - if ( !bInserted ) - push_back( pAttrib ); -} - -void TextCharAttribList::ResortAttribs() -{ - if ( !empty() ) - std::sort( begin(), end(), CompareStart ); -} - -TextCharAttrib* TextCharAttribList::FindAttrib( sal_uInt16 nWhich, sal_uInt16 nPos ) -{ - // Rueckwaerts, falls eins dort endet, das naechste startet. - // => Das startende gilt... - - for ( sal_uInt16 nAttr = size(); nAttr; ) - { - TextCharAttrib* pAttr = GetAttrib( --nAttr ); - - if ( pAttr->GetEnd() < nPos ) - return 0; - - if ( ( pAttr->Which() == nWhich ) && pAttr->IsIn(nPos) ) - return pAttr; - } - return NULL; -} - -TextCharAttrib* TextCharAttribList::FindNextAttrib( sal_uInt16 nWhich, sal_uInt16 nFromPos, sal_uInt16 nMaxPos ) const -{ - DBG_ASSERT( nWhich, "FindNextAttrib: Which?" ); - const sal_uInt16 nAttribs = size(); - for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ ) - { - TextCharAttrib* pAttr = GetAttrib( nAttr ); - if ( ( pAttr->GetStart() >= nFromPos ) && - ( pAttr->GetEnd() <= nMaxPos ) && - ( pAttr->Which() == nWhich ) ) - return pAttr; - } - return NULL; -} - -sal_Bool TextCharAttribList::HasAttrib( sal_uInt16 nWhich ) const -{ - for ( sal_uInt16 nAttr = size(); nAttr; ) - { - const TextCharAttrib* pAttr = GetAttrib( --nAttr ); - if ( pAttr->Which() == nWhich ) - return sal_True; - } - return sal_False; -} - -sal_Bool TextCharAttribList::HasBoundingAttrib( sal_uInt16 nBound ) -{ - // Rueckwaerts, falls eins dort endet, das naechste startet. - // => Das startende gilt... - for ( sal_uInt16 nAttr = size(); nAttr; ) - { - TextCharAttrib* pAttr = GetAttrib( --nAttr ); - - if ( pAttr->GetEnd() < nBound ) - return sal_False; - - if ( ( pAttr->GetStart() == nBound ) || ( pAttr->GetEnd() == nBound ) ) - return sal_True; - } - return sal_False; -} - -TextCharAttrib* TextCharAttribList::FindEmptyAttrib( sal_uInt16 nWhich, sal_uInt16 nPos ) -{ - if ( !mbHasEmptyAttribs ) - return 0; - - const sal_uInt16 nAttribs = size(); - for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ ) - { - TextCharAttrib* pAttr = GetAttrib( nAttr ); - if ( pAttr->GetStart() > nPos ) - return 0; - - if ( ( pAttr->GetStart() == nPos ) && ( pAttr->GetEnd() == nPos ) && ( pAttr->Which() == nWhich ) ) - return pAttr; - } - return 0; -} - -void TextCharAttribList::DeleteEmptyAttribs() -{ - for ( sal_uInt16 nAttr = 0; nAttr < size(); nAttr++ ) - { - TextCharAttrib* pAttr = GetAttrib( nAttr ); - if ( pAttr->IsEmpty() ) - { - erase( begin() + nAttr ); - delete pAttr; - nAttr--; - } - } - mbHasEmptyAttribs = sal_False; -} - -// ------------------------------------------------------------------------- -// (+) class TextNode -// ------------------------------------------------------------------------- - -TextNode::TextNode( const String& rText ) : - maText( rText ) -{ -} - -void TextNode::ExpandAttribs( sal_uInt16 nIndex, sal_uInt16 nNew ) -{ - if ( !nNew ) - return; - - sal_Bool bResort = sal_False; - sal_uInt16 nAttribs = maCharAttribs.Count(); - for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ ) - { - TextCharAttrib* pAttrib = maCharAttribs.GetAttrib( nAttr ); - if ( pAttrib->GetEnd() >= nIndex ) - { - // Alle Attribute hinter der Einfuegeposition verschieben... - if ( pAttrib->GetStart() > nIndex ) - { - pAttrib->MoveForward( nNew ); - } - // 0: Leeres Attribut expandieren, wenn an Einfuegestelle - else if ( pAttrib->IsEmpty() ) - { - // Index nicht pruefen, leeres durfte nur dort liegen. - // Wenn spaeter doch Ueberpruefung: - // Spezialfall: Start == 0; AbsLen == 1, nNew = 1 => Expand, weil durch Absatzumbruch! - // Start <= nIndex, End >= nIndex => Start=End=nIndex! -// if ( pAttrib->GetStart() == nIndex ) - pAttrib->Expand( nNew ); - } - // 1: Attribut startet davor, geht bis Index... - else if ( pAttrib->GetEnd() == nIndex ) // Start muss davor liegen - { - // Nur expandieren, wenn kein Feature, - // und wenn nicht in ExcludeListe! - // Sonst geht z.B. ein UL bis zum neuen ULDB, beide expandieren - if ( !maCharAttribs.FindEmptyAttrib( pAttrib->Which(), nIndex ) ) - { - pAttrib->Expand( nNew ); - } - else - bResort = sal_True; - } - // 2: Attribut startet davor, geht hinter Index... - else if ( ( pAttrib->GetStart() < nIndex ) && ( pAttrib->GetEnd() > nIndex ) ) - { - pAttrib->Expand( nNew ); - } - // 3: Attribut startet auf Index... - else if ( pAttrib->GetStart() == nIndex ) - { - if ( nIndex == 0 ) - { - pAttrib->Expand( nNew ); -// bResort = sal_True; // es gibt ja keine Features mehr... - } - else - pAttrib->MoveForward( nNew ); - } - } - - DBG_ASSERT( pAttrib->GetStart() <= pAttrib->GetEnd(), "Expand: Attribut verdreht!" ); - DBG_ASSERT( ( pAttrib->GetEnd() <= maText.Len() ), "Expand: Attrib groesser als Absatz!" ); - DBG_ASSERT( !pAttrib->IsEmpty(), "Leeres Attribut nach ExpandAttribs?" ); - } - - if ( bResort ) - maCharAttribs.ResortAttribs(); -} - -void TextNode::CollapsAttribs( sal_uInt16 nIndex, sal_uInt16 nDeleted ) -{ - if ( !nDeleted ) - return; - - sal_Bool bResort = sal_False; - sal_uInt16 nEndChanges = nIndex+nDeleted; - - for ( sal_uInt16 nAttr = 0; nAttr < maCharAttribs.Count(); nAttr++ ) - { - TextCharAttrib* pAttrib = maCharAttribs.GetAttrib( nAttr ); - sal_Bool bDelAttr = sal_False; - if ( pAttrib->GetEnd() >= nIndex ) - { - // Alles Attribute hinter der Einfuegeposition verschieben... - if ( pAttrib->GetStart() >= nEndChanges ) - { - pAttrib->MoveBackward( nDeleted ); - } - // 1. Innenliegende Attribute loeschen... - else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() <= nEndChanges ) ) - { - // Spezialfall: Attrubt deckt genau den Bereich ab - // => als leeres Attribut behalten. - if ( ( pAttrib->GetStart() == nIndex ) && ( pAttrib->GetEnd() == nEndChanges ) ) - pAttrib->GetEnd() = nIndex; // leer - else - bDelAttr = sal_True; - } - // 2. Attribut beginnt davor, endet drinnen oder dahinter... - else if ( ( pAttrib->GetStart() <= nIndex ) && ( pAttrib->GetEnd() > nIndex ) ) - { - if ( pAttrib->GetEnd() <= nEndChanges ) // endet drinnen - pAttrib->GetEnd() = nIndex; - else - pAttrib->Collaps( nDeleted ); // endet dahinter - } - // 3. Attribut beginnt drinnen, endet dahinter... - else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() > nEndChanges ) ) - { - // Features duerfen nicht expandieren! - pAttrib->GetStart() = nEndChanges; - pAttrib->MoveBackward( nDeleted ); - } - } - - DBG_ASSERT( pAttrib->GetStart() <= pAttrib->GetEnd(), "Collaps: Attribut verdreht!" ); - DBG_ASSERT( ( pAttrib->GetEnd() <= maText.Len()) || bDelAttr, "Collaps: Attrib groesser als Absatz!" ); - if ( bDelAttr /* || pAttrib->IsEmpty() */ ) - { - bResort = sal_True; - maCharAttribs.RemoveAttrib( nAttr ); - delete pAttrib; - nAttr--; - } - else if ( pAttrib->IsEmpty() ) - maCharAttribs.HasEmptyAttribs() = sal_True; - } - - if ( bResort ) - maCharAttribs.ResortAttribs(); -} - -void TextNode::InsertText( sal_uInt16 nPos, const String& rText ) -{ - maText.Insert( rText, nPos ); - ExpandAttribs( nPos, rText.Len() ); -} - -void TextNode::InsertText( sal_uInt16 nPos, sal_Unicode c ) -{ - maText.Insert( c, nPos ); - ExpandAttribs( nPos, 1 ); -} - -void TextNode::RemoveText( sal_uInt16 nPos, sal_uInt16 nChars ) -{ - maText.Erase( nPos, nChars ); - CollapsAttribs( nPos, nChars ); -} - -TextNode* TextNode::Split( sal_uInt16 nPos, sal_Bool bKeepEndingAttribs ) -{ - String aNewText; - if ( nPos < maText.Len() ) - { - aNewText = maText.Copy( nPos ); - maText.Erase( nPos ); - } - TextNode* pNew = new TextNode( aNewText ); - - for ( sal_uInt16 nAttr = 0; nAttr < maCharAttribs.Count(); nAttr++ ) - { - TextCharAttrib* pAttrib = maCharAttribs.GetAttrib( nAttr ); - if ( pAttrib->GetEnd() < nPos ) - { - // bleiben unveraendert.... - ; - } - else if ( pAttrib->GetEnd() == nPos ) - { - // muessen als leeres Attribut kopiert werden. - // !FindAttrib nur sinnvoll, wenn Rueckwaerts durch Liste! - if ( bKeepEndingAttribs && !pNew->maCharAttribs.FindAttrib( pAttrib->Which(), 0 ) ) - { - TextCharAttrib* pNewAttrib = new TextCharAttrib( *pAttrib ); - pNewAttrib->GetStart() = 0; - pNewAttrib->GetEnd() = 0; - pNew->maCharAttribs.InsertAttrib( pNewAttrib ); - } - } - else if ( pAttrib->IsInside( nPos ) || ( !nPos && !pAttrib->GetStart() ) ) - { - // Wenn ganz vorne gecuttet wird, muss das Attribut erhalten bleiben! - // muessen kopiert und geaendert werden - TextCharAttrib* pNewAttrib = new TextCharAttrib( *pAttrib ); - pNewAttrib->GetStart() = 0; - pNewAttrib->GetEnd() = pAttrib->GetEnd()-nPos; - pNew->maCharAttribs.InsertAttrib( pNewAttrib ); - // stutzen: - pAttrib->GetEnd() = nPos; - } - else - { - DBG_ASSERT( pAttrib->GetStart() >= nPos, "Start < nPos!" ); - DBG_ASSERT( pAttrib->GetEnd() >= nPos, "End < nPos!" ); - // alle dahinter verschieben in den neuen Node (this) - maCharAttribs.RemoveAttrib( nAttr ); - pNew->maCharAttribs.InsertAttrib( pAttrib ); - pAttrib->GetStart() = pAttrib->GetStart() - nPos; - pAttrib->GetEnd() = pAttrib->GetEnd() - nPos; - nAttr--; - } - } - return pNew; -} - -void TextNode::Append( const TextNode& rNode ) -{ - sal_uInt16 nOldLen = maText.Len(); - - maText += rNode.GetText(); - - const sal_uInt16 nAttribs = rNode.GetCharAttribs().Count(); - for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ ) - { - TextCharAttrib* pAttrib = rNode.GetCharAttribs().GetAttrib( nAttr ); - sal_Bool bMelted = sal_False; - if ( pAttrib->GetStart() == 0 ) - { - // Evtl koennen Attribute zusammengefasst werden: - sal_uInt16 nTmpAttribs = maCharAttribs.Count(); - for ( sal_uInt16 nTmpAttr = 0; nTmpAttr < nTmpAttribs; nTmpAttr++ ) - { - TextCharAttrib* pTmpAttrib = maCharAttribs.GetAttrib( nTmpAttr ); - - if ( pTmpAttrib->GetEnd() == nOldLen ) - { - if ( ( pTmpAttrib->Which() == pAttrib->Which() ) && - ( pTmpAttrib->GetAttr() == pAttrib->GetAttr() ) ) - { - pTmpAttrib->GetEnd() = - pTmpAttrib->GetEnd() + pAttrib->GetLen(); - bMelted = sal_True; - break; // es kann nur eins von der Sorte an der Stelle geben - } - } - } - } - - if ( !bMelted ) - { - TextCharAttrib* pNewAttrib = new TextCharAttrib( *pAttrib ); - pNewAttrib->GetStart() = pNewAttrib->GetStart() + nOldLen; - pNewAttrib->GetEnd() = pNewAttrib->GetEnd() + nOldLen; - maCharAttribs.InsertAttrib( pNewAttrib ); - } - } -} - -// ------------------------------------------------------------------------- -// (+) class TextDoc -// ------------------------------------------------------------------------- - -TextDoc::TextDoc() -{ - mnLeftMargin = 0; -}; - -TextDoc::~TextDoc() -{ - DestroyTextNodes(); -} - -void TextDoc::Clear() -{ - DestroyTextNodes(); -} - -void TextDoc::DestroyTextNodes() -{ - for ( sal_uLong nNode = 0; nNode < maTextNodes.Count(); nNode++ ) - delete maTextNodes.GetObject( nNode ); - maTextNodes.clear(); -} - -String TextDoc::GetText( const sal_Unicode* pSep ) const -{ - sal_uLong nLen = GetTextLen( pSep ); - sal_uLong nNodes = maTextNodes.Count(); - - if ( nLen > STRING_MAXLEN ) - { - OSL_FAIL( "Text zu gross fuer String" ); - return String(); - } - - String aASCIIText; - sal_uLong nLastNode = nNodes-1; - for ( sal_uLong nNode = 0; nNode < nNodes; nNode++ ) - { - TextNode* pNode = maTextNodes.GetObject( nNode ); - String aTmp( pNode->GetText() ); - aASCIIText += aTmp; - if ( pSep && ( nNode != nLastNode ) ) - aASCIIText += pSep; - } - - return aASCIIText; -} - -XubString TextDoc::GetText( sal_uLong nPara ) const -{ - XubString aText; - TextNode* pNode = ( nPara < maTextNodes.Count() ) ? maTextNodes.GetObject( nPara ) : 0; - if ( pNode ) - aText = pNode->GetText(); - - return aText; -} - - -sal_uLong TextDoc::GetTextLen( const xub_Unicode* pSep, const TextSelection* pSel ) const -{ - sal_uLong nLen = 0; - sal_uLong nNodes = maTextNodes.Count(); - if ( nNodes ) - { - sal_uLong nStartNode = 0; - sal_uLong nEndNode = nNodes-1; - if ( pSel ) - { - nStartNode = pSel->GetStart().GetPara(); - nEndNode = pSel->GetEnd().GetPara(); - } - - for ( sal_uLong nNode = nStartNode; nNode <= nEndNode; nNode++ ) - { - TextNode* pNode = maTextNodes.GetObject( nNode ); - - sal_uInt16 nS = 0; - sal_uLong nE = pNode->GetText().Len(); - if ( pSel && ( nNode == pSel->GetStart().GetPara() ) ) - nS = pSel->GetStart().GetIndex(); - if ( pSel && ( nNode == pSel->GetEnd().GetPara() ) ) - nE = pSel->GetEnd().GetIndex(); - - nLen += ( nE - nS ); - } - - if ( pSep ) - nLen += (nEndNode-nStartNode) * rtl_ustr_getLength(pSep); - } - - return nLen; -} - -TextPaM TextDoc::InsertText( const TextPaM& rPaM, xub_Unicode c ) -{ - DBG_ASSERT( c != 0x0A, "TextDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" ); - DBG_ASSERT( c != 0x0D, "TextDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" ); - - TextNode* pNode = maTextNodes.GetObject( rPaM.GetPara() ); - pNode->InsertText( rPaM.GetIndex(), c ); - - TextPaM aPaM( rPaM.GetPara(), rPaM.GetIndex()+1 ); - return aPaM; -} - -TextPaM TextDoc::InsertText( const TextPaM& rPaM, const XubString& rStr ) -{ - DBG_ASSERT( rStr.Search( 0x0A ) == STRING_NOTFOUND, "TextDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" ); - DBG_ASSERT( rStr.Search( 0x0D ) == STRING_NOTFOUND, "TextDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" ); - - TextNode* pNode = maTextNodes.GetObject( rPaM.GetPara() ); - pNode->InsertText( rPaM.GetIndex(), rStr ); - - TextPaM aPaM( rPaM.GetPara(), rPaM.GetIndex()+rStr.Len() ); - return aPaM; -} - -TextPaM TextDoc::InsertParaBreak( const TextPaM& rPaM, sal_Bool bKeepEndingAttribs ) -{ - TextNode* pNode = maTextNodes.GetObject( rPaM.GetPara() ); - TextNode* pNew = pNode->Split( rPaM.GetIndex(), bKeepEndingAttribs ); - - maTextNodes.Insert( pNew, rPaM.GetPara()+1 ); - - TextPaM aPaM( rPaM.GetPara()+1, 0 ); - return aPaM; -} - -TextPaM TextDoc::ConnectParagraphs( TextNode* pLeft, TextNode* pRight ) -{ - sal_uInt16 nPrevLen = pLeft->GetText().Len(); - pLeft->Append( *pRight ); - - // der rechte verschwindet. - sal_uLong nRight = maTextNodes.GetPos( pRight ); - maTextNodes.Remove( nRight ); - delete pRight; - - sal_uLong nLeft = maTextNodes.GetPos( pLeft ); - TextPaM aPaM( nLeft, nPrevLen ); - return aPaM; -} - -TextPaM TextDoc::RemoveChars( const TextPaM& rPaM, sal_uInt16 nChars ) -{ - TextNode* pNode = maTextNodes.GetObject( rPaM.GetPara() ); - pNode->RemoveText( rPaM.GetIndex(), nChars ); - - return rPaM; -} - -sal_Bool TextDoc::IsValidPaM( const TextPaM& rPaM ) -{ - if ( rPaM.GetPara() >= maTextNodes.Count() ) - { - OSL_FAIL( "PaM: Para out of range" ); - return sal_False; - } - TextNode * pNode = maTextNodes.GetObject( rPaM.GetPara() ); - if ( rPaM.GetIndex() > pNode->GetText().Len() ) - { - OSL_FAIL( "PaM: Index out of range" ); - return sal_False; - } - return sal_True; -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svtools/source/edit/textdoc.hxx b/svtools/source/edit/textdoc.hxx deleted file mode 100644 index 1551123..0000000 --- a/svtools/source/edit/textdoc.hxx +++ /dev/null @@ -1,145 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2000, 2010 Oracle and/or its affiliates. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * - * for a copy of the LGPLv3 License. - * - ************************************************************************/ - -#ifndef _TEXTDOC_HXX -#define _TEXTDOC_HXX - -#include -#include - -#include -#include - -class TextCharAttribs : public std::vector { -public: - ~TextCharAttribs() - { - for( iterator it = begin(); it != end(); ++it ) - delete *it; - } -}; - -class TextCharAttribList : private TextCharAttribs -{ -private: - sal_Bool mbHasEmptyAttribs; - - TextCharAttribList( const TextCharAttribList& ) : TextCharAttribs() {} - -public: - TextCharAttribList(); - ~TextCharAttribList(); - - void Clear( sal_Bool bDestroyAttribs ); - sal_uInt16 Count() const { return TextCharAttribs::size(); } - - TextCharAttrib* GetAttrib( sal_uInt16 n ) const { return TextCharAttribs::operator[]( n ); } - void RemoveAttrib( sal_uInt16 n ) { TextCharAttribs::erase( begin() + n ); } - - void InsertAttrib( TextCharAttrib* pAttrib ); - - void DeleteEmptyAttribs(); - void ResortAttribs(); - - sal_Bool HasEmptyAttribs() const { return mbHasEmptyAttribs; } - sal_Bool& HasEmptyAttribs() { return mbHasEmptyAttribs; } - - TextCharAttrib* FindAttrib( sal_uInt16 nWhich, sal_uInt16 nPos ); - TextCharAttrib* FindNextAttrib( sal_uInt16 nWhich, sal_uInt16 nFromPos, sal_uInt16 nMaxPos = 0xFFFF ) const; - TextCharAttrib* FindEmptyAttrib( sal_uInt16 nWhich, sal_uInt16 nPos ); - sal_Bool HasAttrib( sal_uInt16 nWhich ) const; - sal_Bool HasBoundingAttrib( sal_uInt16 nBound ); -}; - - -class TextNode -{ -private: - String maText; - TextCharAttribList maCharAttribs; - - TextNode( const TextNode& ) {;} -protected: - void ExpandAttribs( sal_uInt16 nIndex, sal_uInt16 nNewChars ); - void CollapsAttribs( sal_uInt16 nIndex, sal_uInt16 nDelChars ); - -public: - TextNode( const String& rText ); - - - const String& GetText() const { return maText; } - - const TextCharAttribList& GetCharAttribs() const { return maCharAttribs; } - TextCharAttribList& GetCharAttribs() { return maCharAttribs; } - - void InsertText( sal_uInt16 nPos, const String& rText ); - void InsertText( sal_uInt16 nPos, sal_Unicode c ); - void RemoveText( sal_uInt16 nPos, sal_uInt16 nChars ); - - TextNode* Split( sal_uInt16 nPos, sal_Bool bKeepEndigAttribs ); - void Append( const TextNode& rNode ); -}; - -class TextDoc -{ -private: - ToolsList maTextNodes; - sal_uInt16 mnLeftMargin; - -protected: - void DestroyTextNodes(); - -public: - TextDoc(); - ~TextDoc(); - - void Clear(); - - ToolsList& GetNodes() { return maTextNodes; } - const ToolsList& GetNodes() const { return maTextNodes; } - - TextPaM RemoveChars( const TextPaM& rPaM, sal_uInt16 nChars ); - TextPaM InsertText( const TextPaM& rPaM, sal_Unicode c ); - TextPaM InsertText( const TextPaM& rPaM, const String& rStr ); - - TextPaM InsertParaBreak( const TextPaM& rPaM, sal_Bool bKeepEndingAttribs ); - TextPaM ConnectParagraphs( TextNode* pLeft, TextNode* pRight ); - - sal_uLong GetTextLen( const sal_Unicode* pSep, const TextSelection* pSel = NULL ) const; - String GetText( const sal_Unicode* pSep ) const; - String GetText( sal_uLong nPara ) const; - - void SetLeftMargin( sal_uInt16 n ) { mnLeftMargin = n; } - sal_uInt16 GetLeftMargin() const { return mnLeftMargin; } - - sal_Bool IsValidPaM( const TextPaM& rPaM ); -}; - -#endif // _TEXTDOC_HXX - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svtools/source/edit/texteng.cxx b/svtools/source/edit/texteng.cxx deleted file mode 100644 index efce793..0000000 --- a/svtools/source/edit/texteng.cxx +++ /dev/null @@ -1,3205 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2000, 2010 Oracle and/or its affiliates. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * - * for a copy of the LGPLv3 License. - * - ************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include - -#include - -#include -#include -#include - -#include - -#include -#include - -#include -#include - -#include - -#include -#include -#include - -using namespace ::com::sun::star; -using namespace ::com::sun::star::uno; -using namespace ::rtl; - - -// ------------------------------------------------------------------------- -// (-) class TextEngine -// ------------------------------------------------------------------------- -TextEngine::TextEngine() -{ - mpDoc = 0; - mpTEParaPortions = 0; - - mpViews = new TextViews; - mpActiveView = NULL; - - mbIsFormatting = sal_False; - mbFormatted = sal_False; - mbUpdate = sal_True; - mbModified = sal_False; - mbUndoEnabled = sal_False; - mbIsInUndo = sal_False; - mbDowning = sal_False; - mbRightToLeft = sal_False; - mbHasMultiLineParas = sal_False; - - meAlign = TXTALIGN_LEFT; - - mnMaxTextWidth = 0; - mnMaxTextLen = 0; - mnCurTextWidth = 0xFFFFFFFF; - mnCurTextHeight = 0; - - mpUndoManager = NULL; - mpIMEInfos = NULL; - mpLocaleDataWrapper = NULL; - - mpIdleFormatter = new IdleFormatter; - mpIdleFormatter->SetTimeoutHdl( LINK( this, TextEngine, IdleFormatHdl ) ); - - mpRefDev = new VirtualDevice; - - ImpInitLayoutMode( mpRefDev ); - - ImpInitDoc(); - - maTextColor = COL_BLACK; - Font aFont; - aFont.SetTransparent( sal_False ); - Color aFillColor( aFont.GetFillColor() ); - aFillColor.SetTransparency( 0 ); - aFont.SetFillColor( aFillColor ); - SetFont( aFont ); -} - -TextEngine::~TextEngine() -{ - mbDowning = sal_True; - - delete mpIdleFormatter; - delete mpDoc; - delete mpTEParaPortions; - delete mpViews; // nur die Liste, nicht die Vies - delete mpRefDev; - delete mpUndoManager; - delete mpIMEInfos; - delete mpLocaleDataWrapper; -} - -void TextEngine::InsertView( TextView* pTextView ) -{ - mpViews->push_back( pTextView ); - pTextView->SetSelection( TextSelection() ); - - if ( !GetActiveView() ) - SetActiveView( pTextView ); -} - -void TextEngine::RemoveView( TextView* pTextView ) -{ - TextViews::iterator it = std::find( mpViews->begin(), mpViews->end(), pTextView ); - if( it != mpViews->end() ) - { - pTextView->HideCursor(); - mpViews->erase( it ); - if ( pTextView == GetActiveView() ) - SetActiveView( 0 ); - } -} - -sal_uInt16 TextEngine::GetViewCount() const -{ - return mpViews->size(); -} - -TextView* TextEngine::GetView( sal_uInt16 nView ) const -{ - return (*mpViews)[ nView ]; -} - -TextView* TextEngine::GetActiveView() const -{ - return mpActiveView; -} - -void TextEngine::SetActiveView( TextView* pTextView ) -{ - if ( pTextView != mpActiveView ) - { - if ( mpActiveView ) - mpActiveView->HideSelection(); - - mpActiveView = pTextView; - - if ( mpActiveView ) - mpActiveView->ShowSelection(); - } -} - -void TextEngine::SetFont( const Font& rFont ) -{ - if ( rFont != maFont ) - { - maFont = rFont; - // #i40221# As the font's color now defaults to transparent (since i35764) - // we have to choose a useful textcolor in this case. - // Otherwise maTextColor and maFont.GetColor() are both transparent.... - if( rFont.GetColor() == COL_TRANSPARENT ) - maTextColor = COL_BLACK; - else - maTextColor = rFont.GetColor(); - - // Wegen Selektion keinen Transparenten Font zulassen... - // (Sonst spaeter in ImplPaint den Hintergrund anders loeschen...) - maFont.SetTransparent( sal_False ); - // Tell VCL not to use the font color, use text color from OutputDevice - maFont.SetColor( COL_TRANSPARENT ); - Color aFillColor( maFont.GetFillColor() ); - aFillColor.SetTransparency( 0 ); - maFont.SetFillColor( aFillColor ); - - maFont.SetAlign( ALIGN_TOP ); - mpRefDev->SetFont( maFont); - Size aTextSize; - aTextSize.Width() = mpRefDev->GetTextWidth(rtl::OUString(" ")); - aTextSize.Height() = mpRefDev->GetTextHeight(); - if ( !aTextSize.Width() ) - aTextSize.Width() = mpRefDev->GetTextWidth(rtl::OUString("XXXX")); - - mnDefTab = (sal_uInt16)aTextSize.Width(); - if ( !mnDefTab ) - mnDefTab = 1; - mnCharHeight = (sal_uInt16)aTextSize.Height(); - mnFixCharWidth100 = 0; - - FormatFullDoc(); - UpdateViews(); - - for ( sal_uInt16 nView = mpViews->size(); nView; ) - { - TextView* pView = (*mpViews)[ --nView ]; - pView->GetWindow()->SetInputContext( InputContext( GetFont(), !pView->IsReadOnly() ? INPUTCONTEXT_TEXT|INPUTCONTEXT_EXTTEXTINPUT : 0 ) ); - } - } -} - -void TextEngine::SetMaxTextLen( sal_uLong nLen ) -{ - mnMaxTextLen = nLen; -} - -void TextEngine::SetMaxTextWidth( sal_uLong nMaxWidth ) -{ - if ( nMaxWidth != mnMaxTextWidth ) - { - mnMaxTextWidth = Min( nMaxWidth, (sal_uLong)0x7FFFFFFF ); - FormatFullDoc(); - UpdateViews(); - } -} - -static sal_Unicode static_aLFText[] = { '\n', 0 }; -static sal_Unicode static_aCRText[] = { '\r', 0 }; -static sal_Unicode static_aCRLFText[] = { '\r', '\n', 0 }; - -static inline const sal_Unicode* static_getLineEndText( LineEnd aLineEnd ) -{ - const sal_Unicode* pRet = NULL; - - switch( aLineEnd ) - { - case LINEEND_LF: pRet = static_aLFText;break; - case LINEEND_CR: pRet = static_aCRText;break; - case LINEEND_CRLF: pRet = static_aCRLFText;break; - } - return pRet; -} - -void TextEngine::ReplaceText(const TextSelection& rSel, const String& rText) -{ - ImpInsertText( rSel, rText ); -} - -String TextEngine::GetText( LineEnd aSeparator ) const -{ - return mpDoc->GetText( static_getLineEndText( aSeparator ) ); -} - -String TextEngine::GetTextLines( LineEnd aSeparator ) const -{ - String aText; - sal_uLong nParas = mpTEParaPortions->Count(); - const sal_Unicode* pSep = static_getLineEndText( aSeparator ); - for ( sal_uLong nP = 0; nP < nParas; nP++ ) - { - TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nP ); - - sal_uInt16 nLines = pTEParaPortion->GetLines().size(); - for ( sal_uInt16 nL = 0; nL < nLines; nL++ ) - { - TextLine* pLine = pTEParaPortion->GetLines()[nL]; - aText += pTEParaPortion->GetNode()->GetText().Copy( pLine->GetStart(), pLine->GetEnd() - pLine->GetStart() ); - if ( pSep && ( ( (nP+1) < nParas ) || ( (nL+1) < nLines ) ) ) - aText += pSep; - } - } - return aText; -} - -String TextEngine::GetText( sal_uLong nPara ) const -{ - return mpDoc->GetText( nPara ); -} - -sal_uLong TextEngine::GetTextLen( LineEnd aSeparator ) const -{ - return mpDoc->GetTextLen( static_getLineEndText( aSeparator ) ); -} - -sal_uLong TextEngine::GetTextLen( const TextSelection& rSel, LineEnd aSeparator ) const -{ - TextSelection aSel( rSel ); - aSel.Justify(); - ValidateSelection( aSel ); - return mpDoc->GetTextLen( static_getLineEndText( aSeparator ), &aSel ); -} - -sal_uInt16 TextEngine::GetTextLen( sal_uLong nPara ) const -{ - return mpDoc->GetNodes().GetObject( nPara )->GetText().Len(); -} - -void TextEngine::SetUpdateMode( sal_Bool bUpdate ) -{ - if ( bUpdate != mbUpdate ) - { - mbUpdate = bUpdate; - if ( mbUpdate ) - { - FormatAndUpdate( GetActiveView() ); - if ( GetActiveView() ) - GetActiveView()->ShowCursor(); - } - } -} - -sal_Bool TextEngine::DoesKeyChangeText( const KeyEvent& rKeyEvent ) -{ - sal_Bool bDoesChange = sal_False; - - KeyFuncType eFunc = rKeyEvent.GetKeyCode().GetFunction(); - if ( eFunc != KEYFUNC_DONTKNOW ) - { - switch ( eFunc ) - { - case KEYFUNC_UNDO: - case KEYFUNC_REDO: - case KEYFUNC_CUT: - case KEYFUNC_PASTE: bDoesChange = sal_True; - break; - default: // wird dann evtl. unten bearbeitet. - eFunc = KEYFUNC_DONTKNOW; - } - } - if ( eFunc == KEYFUNC_DONTKNOW ) - { - switch ( rKeyEvent.GetKeyCode().GetCode() ) - { - case KEY_DELETE: - case KEY_BACKSPACE: - { - if ( !rKeyEvent.GetKeyCode().IsMod2() ) - bDoesChange = sal_True; - } - break; - case KEY_RETURN: - case KEY_TAB: - { - if ( !rKeyEvent.GetKeyCode().IsMod1() && !rKeyEvent.GetKeyCode().IsMod2() ) - bDoesChange = sal_True; - } - break; - default: - { - bDoesChange = TextEngine::IsSimpleCharInput( rKeyEvent ); - } - } - } - return bDoesChange; -} - -sal_Bool TextEngine::IsSimpleCharInput( const KeyEvent& rKeyEvent ) -{ - if( rKeyEvent.GetCharCode() >= 32 && rKeyEvent.GetCharCode() != 127 && - KEY_MOD1 != (rKeyEvent.GetKeyCode().GetModifier() & ~KEY_SHIFT) && // (ssa) #i45714#: - KEY_MOD2 != (rKeyEvent.GetKeyCode().GetModifier() & ~KEY_SHIFT) ) // check for Ctrl and Alt separately - { - return sal_True; - } - return sal_False; -} - -void TextEngine::ImpInitDoc() -{ - if ( mpDoc ) - mpDoc->Clear(); - else - mpDoc = new TextDoc; - - delete mpTEParaPortions; - mpTEParaPortions = new TEParaPortions; - - TextNode* pNode = new TextNode( String() ); - mpDoc->GetNodes().Insert( pNode, 0 ); - - TEParaPortion* pIniPortion = new TEParaPortion( pNode ); - mpTEParaPortions->Insert( pIniPortion, (sal_uLong)0 ); - - mbFormatted = sal_False; - - ImpParagraphRemoved( TEXT_PARA_ALL ); - ImpParagraphInserted( 0 ); -} - -String TextEngine::GetText( const TextSelection& rSel, LineEnd aSeparator ) const -{ - String aText; - - if ( !rSel.HasRange() ) - return aText; - - TextSelection aSel( rSel ); - aSel.Justify(); - - sal_uLong nStartPara = aSel.GetStart().GetPara(); - sal_uLong nEndPara = aSel.GetEnd().GetPara(); - const sal_Unicode* pSep = static_getLineEndText( aSeparator ); - for ( sal_uLong nNode = aSel.GetStart().GetPara(); nNode <= nEndPara; nNode++ ) - { - TextNode* pNode = mpDoc->GetNodes().GetObject( nNode ); - - sal_uInt16 nStartPos = 0; - sal_uInt16 nEndPos = pNode->GetText().Len(); - if ( nNode == nStartPara ) - nStartPos = aSel.GetStart().GetIndex(); - if ( nNode == nEndPara ) // kann auch == nStart sein! - nEndPos = aSel.GetEnd().GetIndex(); - - aText += pNode->GetText().Copy( nStartPos, nEndPos-nStartPos ); - if ( nNode < nEndPara ) - aText += pSep; - } - return aText; -} - -void TextEngine::ImpRemoveText() -{ - ImpInitDoc(); - - TextPaM aStartPaM( 0, 0 ); - TextSelection aEmptySel( aStartPaM, aStartPaM ); - for ( sal_uInt16 nView = 0; nView < mpViews->size(); nView++ ) - { - TextView* pView = (*mpViews)[ nView ]; - pView->ImpSetSelection( aEmptySel ); - } - ResetUndo(); -} - -void TextEngine::SetText( const XubString& rText ) -{ - ImpRemoveText(); - - sal_Bool bUndoCurrentlyEnabled = IsUndoEnabled(); - // Der von Hand reingesteckte Text kann nicht vom Anwender rueckgaengig gemacht werden. - EnableUndo( sal_False ); - - TextPaM aStartPaM( 0, 0 ); - TextSelection aEmptySel( aStartPaM, aStartPaM ); - - TextPaM aPaM = aStartPaM; - if ( rText.Len() ) - aPaM = ImpInsertText( aEmptySel, rText ); - - for ( sal_uInt16 nView = 0; nView < mpViews->size(); nView++ ) - { - TextView* pView = (*mpViews)[ nView ]; - pView->ImpSetSelection( aEmptySel ); - - // Wenn kein Text, dann auch Kein Format&Update - // => Der Text bleibt stehen. - if ( !rText.Len() && GetUpdateMode() ) - pView->Invalidate(); - } - - if( !rText.Len() ) // sonst muss spaeter noch invalidiert werden, !bFormatted reicht. - mnCurTextHeight = 0; - - FormatAndUpdate(); - - EnableUndo( bUndoCurrentlyEnabled ); - DBG_ASSERT( !HasUndoManager() || !GetUndoManager().GetUndoActionCount(), "Undo nach SetText?" ); -} - - -void TextEngine::CursorMoved( sal_uLong nNode ) -{ - // Leere Attribute loeschen, aber nur, wenn Absatz nicht leer! - TextNode* pNode = mpDoc->GetNodes().GetObject( nNode ); - if ( pNode && pNode->GetCharAttribs().HasEmptyAttribs() && pNode->GetText().Len() ) - pNode->GetCharAttribs().DeleteEmptyAttribs(); -} - -void TextEngine::ImpRemoveChars( const TextPaM& rPaM, sal_uInt16 nChars, SfxUndoAction* ) -{ - DBG_ASSERT( nChars, "ImpRemoveChars - 0 Chars?!" ); - if ( IsUndoEnabled() && !IsInUndo() ) - { - // Attribute muessen hier vorm RemoveChars fuer UNDO gesichert werden! - TextNode* pNode = mpDoc->GetNodes().GetObject( rPaM.GetPara() ); - XubString aStr( pNode->GetText().Copy( rPaM.GetIndex(), nChars ) ); - - // Pruefen, ob Attribute geloescht oder geaendert werden: - sal_uInt16 nStart = rPaM.GetIndex(); - sal_uInt16 nEnd = nStart + nChars; - for ( sal_uInt16 nAttr = pNode->GetCharAttribs().Count(); nAttr; ) - { - TextCharAttrib* pAttr = pNode->GetCharAttribs().GetAttrib( --nAttr ); - if ( ( pAttr->GetEnd() >= nStart ) && ( pAttr->GetStart() < nEnd ) ) - { - break; // for - } - } - InsertUndo( new TextUndoRemoveChars( this, rPaM, aStr ) ); - } - - mpDoc->RemoveChars( rPaM, nChars ); - ImpCharsRemoved( rPaM.GetPara(), rPaM.GetIndex(), nChars ); -} - -TextPaM TextEngine::ImpConnectParagraphs( sal_uLong nLeft, sal_uLong nRight ) -{ - DBG_ASSERT( nLeft != nRight, "Den gleichen Absatz zusammenfuegen ?" ); - - TextNode* pLeft = mpDoc->GetNodes().GetObject( nLeft ); - TextNode* pRight = mpDoc->GetNodes().GetObject( nRight ); - - if ( IsUndoEnabled() && !IsInUndo() ) - InsertUndo( new TextUndoConnectParas( this, nLeft, pLeft->GetText().Len() ) ); - - // Erstmal Portions suchen, da pRight nach ConnectParagraphs weg. - TEParaPortion* pLeftPortion = mpTEParaPortions->GetObject( nLeft ); - TEParaPortion* pRightPortion = mpTEParaPortions->GetObject( nRight ); - DBG_ASSERT( pLeft && pLeftPortion, "Blinde Portion in ImpConnectParagraphs(1)" ); - DBG_ASSERT( pRight && pRightPortion, "Blinde Portion in ImpConnectParagraphs(2)" ); - - TextPaM aPaM = mpDoc->ConnectParagraphs( pLeft, pRight ); - ImpParagraphRemoved( nRight ); - - pLeftPortion->MarkSelectionInvalid( aPaM.GetIndex(), pLeft->GetText().Len() ); - - mpTEParaPortions->Remove( nRight ); - delete pRightPortion; - // der rechte Node wird von EditDoc::ConnectParagraphs() geloescht. - - return aPaM; -} - -TextPaM TextEngine::ImpDeleteText( const TextSelection& rSel ) -{ - if ( !rSel.HasRange() ) - return rSel.GetStart(); - - TextSelection aSel( rSel ); - aSel.Justify(); - TextPaM aStartPaM( aSel.GetStart() ); - TextPaM aEndPaM( aSel.GetEnd() ); - - CursorMoved( aStartPaM.GetPara() ); // nur damit neu eingestellte Attribute verschwinden... - CursorMoved( aEndPaM.GetPara() ); // nur damit neu eingestellte Attribute verschwinden... - - DBG_ASSERT( mpDoc->IsValidPaM( aStartPaM ), "Index im Wald in ImpDeleteText" ); - DBG_ASSERT( mpDoc->IsValidPaM( aEndPaM ), "Index im Wald in ImpDeleteText" ); - - sal_uLong nStartNode = aStartPaM.GetPara(); - sal_uLong nEndNode = aEndPaM.GetPara(); - - // Alle Nodes dazwischen entfernen.... - for ( sal_uLong z = nStartNode+1; z < nEndNode; z++ ) - { - // Immer nStartNode+1, wegen Remove()! - ImpRemoveParagraph( nStartNode+1 ); - } - - if ( nStartNode != nEndNode ) - { - // Den Rest des StartNodes... - TextNode* pLeft = mpDoc->GetNodes().GetObject( nStartNode ); - sal_uInt16 nChars = pLeft->GetText().Len() - aStartPaM.GetIndex(); - if ( nChars ) - { - ImpRemoveChars( aStartPaM, nChars ); - TEParaPortion* pPortion = mpTEParaPortions->GetObject( nStartNode ); - DBG_ASSERT( pPortion, "Blinde Portion in ImpDeleteText(3)" ); - pPortion->MarkSelectionInvalid( aStartPaM.GetIndex(), pLeft->GetText().Len() ); - } - - // Den Anfang des EndNodes.... - nEndNode = nStartNode+1; // Die anderen Absaetze wurden geloescht - nChars = aEndPaM.GetIndex(); - if ( nChars ) - { - aEndPaM.GetPara() = nEndNode; - aEndPaM.GetIndex() = 0; - ImpRemoveChars( aEndPaM, nChars ); - TEParaPortion* pPortion = mpTEParaPortions->GetObject( nEndNode ); - DBG_ASSERT( pPortion, "Blinde Portion in ImpDeleteText(4)" ); - pPortion->MarkSelectionInvalid( 0, pPortion->GetNode()->GetText().Len() ); - } - - // Zusammenfuegen.... - aStartPaM = ImpConnectParagraphs( nStartNode, nEndNode ); - } - else - { - sal_uInt16 nChars; - nChars = aEndPaM.GetIndex() - aStartPaM.GetIndex(); - ImpRemoveChars( aStartPaM, nChars ); - TEParaPortion* pPortion = mpTEParaPortions->GetObject( nStartNode ); - DBG_ASSERT( pPortion, "Blinde Portion in ImpDeleteText(5)" ); - pPortion->MarkInvalid( aEndPaM.GetIndex(), aStartPaM.GetIndex() - aEndPaM.GetIndex() ); - } - -// UpdateSelections(); - TextModified(); - return aStartPaM; -} - -void TextEngine::ImpRemoveParagraph( sal_uLong nPara ) -{ - TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); - TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPara ); - - // Der Node wird vom Undo verwaltet und ggf. zerstoert! - /* delete */ mpDoc->GetNodes().Remove( nPara ); - if ( IsUndoEnabled() && !IsInUndo() ) - InsertUndo( new TextUndoDelPara( this, pNode, nPara ) ); - else - delete pNode; - - mpTEParaPortions->Remove( nPara ); - delete pPortion; - - ImpParagraphRemoved( nPara ); -} - -uno::Reference < i18n::XExtendedInputSequenceChecker > TextEngine::GetInputSequenceChecker() const -{ - uno::Reference < i18n::XExtendedInputSequenceChecker > xISC; -// if ( !xISC.is() ) - { - uno::Reference< lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory(); - uno::Reference< uno::XInterface > xI = xMSF->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.i18n.InputSequenceChecker" )) ); - if ( xI.is() ) - { - Any x = xI->queryInterface( ::getCppuType((const uno::Reference< i18n::XExtendedInputSequenceChecker >*)0) ); - x >>= xISC; - } - } - return xISC; -} - -sal_Bool TextEngine::IsInputSequenceCheckingRequired( sal_Unicode c, const TextSelection& rCurSel ) const -{ - uno::Reference< i18n::XBreakIterator > xBI = ((TextEngine *) this)->GetBreakIterator(); - SvtCTLOptions aCTLOptions; - - // get the index that really is first - sal_uInt16 nFirstPos = rCurSel.GetStart().GetIndex(); - sal_uInt16 nMaxPos = rCurSel.GetEnd().GetIndex(); - if (nMaxPos < nFirstPos) - nFirstPos = nMaxPos; - - sal_Bool bIsSequenceChecking = - aCTLOptions.IsCTLFontEnabled() && - aCTLOptions.IsCTLSequenceChecking() && - nFirstPos != 0 && /* first char needs not to be checked */ - xBI.is() && i18n::ScriptType::COMPLEX == xBI->getScriptType( rtl::OUString( c ), 0 ); - - return bIsSequenceChecking; -} - -TextPaM TextEngine::ImpInsertText( const TextSelection& rCurSel, sal_Unicode c, sal_Bool bOverwrite ) -{ - return ImpInsertText( c, rCurSel, bOverwrite, sal_False ); -} - -TextPaM TextEngine::ImpInsertText( sal_Unicode c, const TextSelection& rCurSel, sal_Bool bOverwrite, sal_Bool bIsUserInput ) -{ - DBG_ASSERT( c != '\n', "Zeilenumbruch bei InsertText ?" ); - DBG_ASSERT( c != '\r', "Zeilenumbruch bei InsertText ?" ); - - TextPaM aPaM( rCurSel.GetStart() ); - TextNode* pNode = mpDoc->GetNodes().GetObject( aPaM.GetPara() ); - - if ( pNode->GetText().Len() < STRING_MAXLEN ) - { - sal_Bool bDoOverwrite = ( bOverwrite && - ( aPaM.GetIndex() < pNode->GetText().Len() ) ) ? sal_True : sal_False; - - sal_Bool bUndoAction = ( rCurSel.HasRange() || bDoOverwrite ); - - if ( bUndoAction ) - UndoActionStart(); - - if ( rCurSel.HasRange() ) - { - aPaM = ImpDeleteText( rCurSel ); - } - else if ( bDoOverwrite ) - { - // Wenn Selektion, dann kein Zeichen ueberschreiben - TextSelection aTmpSel( aPaM ); - aTmpSel.GetEnd().GetIndex()++; - ImpDeleteText( aTmpSel ); - } - - if (bIsUserInput && IsInputSequenceCheckingRequired( c, rCurSel )) - { - uno::Reference < i18n::XExtendedInputSequenceChecker > xISC = GetInputSequenceChecker(); - SvtCTLOptions aCTLOptions; - - if (xISC.is()) - { - xub_StrLen nTmpPos = aPaM.GetIndex(); - sal_Int16 nCheckMode = aCTLOptions.IsCTLSequenceCheckingRestricted() ? - i18n::InputSequenceCheckMode::STRICT : i18n::InputSequenceCheckMode::BASIC; - - // the text that needs to be checked is only the one - // before the current cursor position - rtl::OUString aOldText( mpDoc->GetText( aPaM.GetPara() ).Copy(0, nTmpPos) ); - rtl::OUString aNewText( aOldText ); - if (aCTLOptions.IsCTLSequenceCheckingTypeAndReplace()) - { - xISC->correctInputSequence( aNewText, nTmpPos - 1, c, nCheckMode ); - - // find position of first character that has changed - sal_Int32 nOldLen = aOldText.getLength(); - sal_Int32 nNewLen = aNewText.getLength(); - const sal_Unicode *pOldTxt = aOldText.getStr(); - const sal_Unicode *pNewTxt = aNewText.getStr(); - sal_Int32 nChgPos = 0; - while ( nChgPos < nOldLen && nChgPos < nNewLen && - pOldTxt[nChgPos] == pNewTxt[nChgPos] ) - ++nChgPos; - - String aChgText( aNewText.copy( nChgPos ) ); - - // select text from first pos to be changed to current pos - TextSelection aSel( TextPaM( aPaM.GetPara(), (sal_uInt16) nChgPos ), aPaM ); - - if (aChgText.Len()) - // ImpInsertText implicitly handles undo... - return ImpInsertText( aSel, aChgText ); - else - return aPaM; - } - else - { - // should the character be ignored (i.e. not get inserted) ? - if (!xISC->checkInputSequence( aOldText, nTmpPos - 1, c, nCheckMode )) - return aPaM; // nothing to be done -> no need for undo - } - } - - // at this point now we will insert the character 'normally' some lines below... - } - - - if ( IsUndoEnabled() && !IsInUndo() ) - { - TextUndoInsertChars* pNewUndo = new TextUndoInsertChars( this, aPaM, rtl::OUString(c) ); - sal_Bool bTryMerge = ( !bDoOverwrite && ( c != ' ' ) ) ? sal_True : sal_False; - InsertUndo( pNewUndo, bTryMerge ); - } - - TEParaPortion* pPortion = mpTEParaPortions->GetObject( aPaM.GetPara() ); - pPortion->MarkInvalid( aPaM.GetIndex(), 1 ); - if ( c == '\t' ) - pPortion->SetNotSimpleInvalid(); - aPaM = mpDoc->InsertText( aPaM, c ); - ImpCharsInserted( aPaM.GetPara(), aPaM.GetIndex()-1, 1 ); - - TextModified(); - - if ( bUndoAction ) - UndoActionEnd(); - } - - return aPaM; -} - - -TextPaM TextEngine::ImpInsertText( const TextSelection& rCurSel, const XubString& rStr ) -{ - UndoActionStart(); - - TextPaM aPaM; - - if ( rCurSel.HasRange() ) - aPaM = ImpDeleteText( rCurSel ); - else - aPaM = rCurSel.GetEnd(); - - XubString aText(convertLineEnd(rStr, LINEEND_LF)); - - sal_uInt16 nStart = 0; - while ( nStart < aText.Len() ) - { - sal_uInt16 nEnd = aText.Search( LINE_SEP, nStart ); - if ( nEnd == STRING_NOTFOUND ) - nEnd = aText.Len(); // nicht dereferenzieren! - - // Start == End => Leerzeile - if ( nEnd > nStart ) - { - sal_uLong nL = aPaM.GetIndex(); - nL += ( nEnd-nStart ); - if ( nL > STRING_MAXLEN ) - { - sal_uInt16 nDiff = (sal_uInt16) (nL-STRING_MAXLEN); - nEnd = nEnd - nDiff; - } - - XubString aLine( aText, nStart, nEnd-nStart ); - if ( IsUndoEnabled() && !IsInUndo() ) - InsertUndo( new TextUndoInsertChars( this, aPaM, aLine ) ); - - TEParaPortion* pPortion = mpTEParaPortions->GetObject( aPaM.GetPara() ); - pPortion->MarkInvalid( aPaM.GetIndex(), aLine.Len() ); - if ( aLine.Search( '\t' ) != STRING_NOTFOUND ) - pPortion->SetNotSimpleInvalid(); - - aPaM = mpDoc->InsertText( aPaM, aLine ); - ImpCharsInserted( aPaM.GetPara(), aPaM.GetIndex()-aLine.Len(), aLine.Len() ); - - } - if ( nEnd < aText.Len() ) - aPaM = ImpInsertParaBreak( aPaM ); - - nStart = nEnd+1; - - if ( nStart < nEnd ) // #108611# overflow - break; - } - - UndoActionEnd(); - - TextModified(); - return aPaM; -} - -TextPaM TextEngine::ImpInsertParaBreak( const TextSelection& rCurSel, sal_Bool bKeepEndingAttribs ) -{ - TextPaM aPaM; - if ( rCurSel.HasRange() ) - aPaM = ImpDeleteText( rCurSel ); - else - aPaM = rCurSel.GetEnd(); - - return ImpInsertParaBreak( aPaM, bKeepEndingAttribs ); -} - -TextPaM TextEngine::ImpInsertParaBreak( const TextPaM& rPaM, sal_Bool bKeepEndingAttribs ) -{ - if ( IsUndoEnabled() && !IsInUndo() ) - InsertUndo( new TextUndoSplitPara( this, rPaM.GetPara(), rPaM.GetIndex() ) ); - - TextNode* pNode = mpDoc->GetNodes().GetObject( rPaM.GetPara() ); - sal_Bool bFirstParaContentChanged = rPaM.GetIndex() < pNode->GetText().Len(); - - TextPaM aPaM( mpDoc->InsertParaBreak( rPaM, bKeepEndingAttribs ) ); - - TEParaPortion* pPortion = mpTEParaPortions->GetObject( rPaM.GetPara() ); - DBG_ASSERT( pPortion, "Blinde Portion in ImpInsertParaBreak" ); - pPortion->MarkInvalid( rPaM.GetIndex(), 0 ); - - TextNode* pNewNode = mpDoc->GetNodes().GetObject( aPaM.GetPara() ); - TEParaPortion* pNewPortion = new TEParaPortion( pNewNode ); - mpTEParaPortions->Insert( pNewPortion, aPaM.GetPara() ); - ImpParagraphInserted( aPaM.GetPara() ); - - CursorMoved( rPaM.GetPara() ); // falls leeres Attribut entstanden. - TextModified(); - - if ( bFirstParaContentChanged ) - Broadcast( TextHint( TEXT_HINT_PARACONTENTCHANGED, rPaM.GetPara() ) ); - - return aPaM; -} - -Rectangle TextEngine::PaMtoEditCursor( const TextPaM& rPaM, sal_Bool bSpecial ) -{ - DBG_ASSERT( GetUpdateMode(), "Darf bei Update=sal_False nicht erreicht werden: PaMtoEditCursor" ); - - Rectangle aEditCursor; - long nY = 0; - - if ( !mbHasMultiLineParas ) - { - nY = rPaM.GetPara() * mnCharHeight; - } - else - { - for ( sal_uLong nPortion = 0; nPortion < rPaM.GetPara(); nPortion++ ) - { - TEParaPortion* pPortion = mpTEParaPortions->GetObject(nPortion); - nY += pPortion->GetLines().size() * mnCharHeight; - } - } - - aEditCursor = GetEditCursor( rPaM, bSpecial ); - aEditCursor.Top() += nY; - aEditCursor.Bottom() += nY; - return aEditCursor; -} - -Rectangle TextEngine::GetEditCursor( const TextPaM& rPaM, sal_Bool bSpecial, sal_Bool bPreferPortionStart ) -{ - if ( !IsFormatted() && !IsFormatting() ) - FormatAndUpdate(); - - TEParaPortion* pPortion = mpTEParaPortions->GetObject( rPaM.GetPara() ); - //TextNode* pNode = mpDoc->GetNodes().GetObject( rPaM.GetPara() ); - - /* - bSpecial: Wenn hinter dem letzten Zeichen einer umgebrochenen Zeile, - am Ende der Zeile bleiben, nicht am Anfang der naechsten. - Zweck: - END => wirklich hinter das letzte Zeichen - - Selektion.... - bSpecial: If behind the last character of a made up line, stay at the - end of the line, not at the start of the next line. - Purpose: - really END = > behind the last character - - to selection... - - */ - - long nY = 0; - sal_uInt16 nCurIndex = 0; - TextLine* pLine = 0; - for ( sal_uInt16 nLine = 0; nLine < pPortion->GetLines().size(); nLine++ ) - { - TextLine* pTmpLine = pPortion->GetLines()[ nLine ]; - if ( ( pTmpLine->GetStart() == rPaM.GetIndex() ) || ( pTmpLine->IsIn( rPaM.GetIndex(), bSpecial ) ) ) - { - pLine = pTmpLine; - break; - } - - nCurIndex = nCurIndex + pTmpLine->GetLen(); - nY += mnCharHeight; - } - if ( !pLine ) - { - // Cursor am Ende des Absatzes. - DBG_ASSERT( rPaM.GetIndex() == nCurIndex, "Index voll daneben in GetEditCursor!" ); - - pLine = pPortion->GetLines().back(); - nY -= mnCharHeight; - nCurIndex = nCurIndex - pLine->GetLen(); - } - - Rectangle aEditCursor; - - aEditCursor.Top() = nY; - nY += mnCharHeight; - aEditCursor.Bottom() = nY-1; - - // innerhalb der Zeile suchen.... - long nX = ImpGetXPos( rPaM.GetPara(), pLine, rPaM.GetIndex(), bPreferPortionStart ); - aEditCursor.Left() = aEditCursor.Right() = nX; - return aEditCursor; -} - -long TextEngine::ImpGetXPos( sal_uLong nPara, TextLine* pLine, sal_uInt16 nIndex, sal_Bool bPreferPortionStart ) -{ - DBG_ASSERT( ( nIndex >= pLine->GetStart() ) && ( nIndex <= pLine->GetEnd() ) , "ImpGetXPos muss richtig gerufen werden!" ); - - sal_Bool bDoPreferPortionStart = bPreferPortionStart; - // Assure that the portion belongs to this line: - if ( nIndex == pLine->GetStart() ) - bDoPreferPortionStart = sal_True; - else if ( nIndex == pLine->GetEnd() ) - bDoPreferPortionStart = sal_False; - - TEParaPortion* pParaPortion = mpTEParaPortions->GetObject( nPara ); - - sal_uInt16 nTextPortionStart = 0; - size_t nTextPortion = pParaPortion->GetTextPortions().FindPortion( nIndex, nTextPortionStart, bDoPreferPortionStart ); - - DBG_ASSERT( ( nTextPortion >= pLine->GetStartPortion() ) && ( nTextPortion <= pLine->GetEndPortion() ), "GetXPos: Portion not in current line! " ); - - TETextPortion* pPortion = pParaPortion->GetTextPortions()[ nTextPortion ]; - - long nX = ImpGetPortionXOffset( nPara, pLine, nTextPortion ); - - long nPortionTextWidth = pPortion->GetWidth(); - - if ( nTextPortionStart != nIndex ) - { - // Search within portion... - if ( nIndex == ( nTextPortionStart + pPortion->GetLen() ) ) - { - // End of Portion - if ( ( pPortion->GetKind() == PORTIONKIND_TAB ) || - ( !IsRightToLeft() && !pPortion->IsRightToLeft() ) || - ( IsRightToLeft() && pPortion->IsRightToLeft() ) ) - { - nX += nPortionTextWidth; - if ( ( pPortion->GetKind() == PORTIONKIND_TAB ) && ( (nTextPortion+1) < pParaPortion->GetTextPortions().size() ) ) - { - TETextPortion* pNextPortion = pParaPortion->GetTextPortions()[ nTextPortion+1 ]; - if ( ( pNextPortion->GetKind() != PORTIONKIND_TAB ) && ( - ( !IsRightToLeft() && pNextPortion->IsRightToLeft() ) || - ( IsRightToLeft() && !pNextPortion->IsRightToLeft() ) ) ) - { -// nX += pNextPortion->GetWidth(); - // End of the tab portion, use start of next for cursor pos - DBG_ASSERT( !bPreferPortionStart, "ImpGetXPos - How can we this tab portion here???" ); - nX = ImpGetXPos( nPara, pLine, nIndex, sal_True ); - } - - } - } - } - else if ( pPortion->GetKind() == PORTIONKIND_TEXT ) - { - DBG_ASSERT( nIndex != pLine->GetStart(), "Strange behavior in new ImpGetXPos()" ); - - long nPosInPortion = (long)CalcTextWidth( nPara, nTextPortionStart, nIndex-nTextPortionStart ); - - if ( ( !IsRightToLeft() && !pPortion->IsRightToLeft() ) || - ( IsRightToLeft() && pPortion->IsRightToLeft() ) ) - { - nX += nPosInPortion; - } - else - { - nX += nPortionTextWidth - nPosInPortion; - } - } - } - else // if ( nIndex == pLine->GetStart() ) - { - if ( ( pPortion->GetKind() != PORTIONKIND_TAB ) && - ( ( !IsRightToLeft() && pPortion->IsRightToLeft() ) || - ( IsRightToLeft() && !pPortion->IsRightToLeft() ) ) ) - { - nX += nPortionTextWidth; - } - } - - return nX; -} - -const TextAttrib* TextEngine::FindAttrib( const TextPaM& rPaM, sal_uInt16 nWhich ) const -{ - const TextAttrib* pAttr = NULL; - const TextCharAttrib* pCharAttr = FindCharAttrib( rPaM, nWhich ); - if ( pCharAttr ) - pAttr = &pCharAttr->GetAttr(); - return pAttr; -} - -const TextCharAttrib* TextEngine::FindCharAttrib( const TextPaM& rPaM, sal_uInt16 nWhich ) const -{ - const TextCharAttrib* pAttr = NULL; - TextNode* pNode = mpDoc->GetNodes().GetObject( rPaM.GetPara() ); - if ( pNode && ( rPaM.GetIndex() < pNode->GetText().Len() ) ) - pAttr = pNode->GetCharAttribs().FindAttrib( nWhich, rPaM.GetIndex() ); - return pAttr; -} - -sal_Bool TextEngine::HasAttrib( sal_uInt16 nWhich ) const -{ - sal_Bool bAttr = sal_False; - for ( sal_uLong n = mpDoc->GetNodes().Count(); --n && !bAttr; ) - { - TextNode* pNode = mpDoc->GetNodes().GetObject( n ); - bAttr = pNode->GetCharAttribs().HasAttrib( nWhich ); - } - return bAttr; -} - -TextPaM TextEngine::GetPaM( const Point& rDocPos, sal_Bool bSmart ) -{ - DBG_ASSERT( GetUpdateMode(), "Darf bei Update=sal_False nicht erreicht werden: GetPaM" ); - - long nY = 0; - for ( sal_uLong nPortion = 0; nPortion < mpTEParaPortions->Count(); nPortion++ ) - { - TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPortion ); - long nTmpHeight = pPortion->GetLines().size() * mnCharHeight; - nY += nTmpHeight; - if ( nY > rDocPos.Y() ) - { - nY -= nTmpHeight; - Point aPosInPara( rDocPos ); - aPosInPara.Y() -= nY; - - TextPaM aPaM( nPortion, 0 ); - aPaM.GetIndex() = ImpFindIndex( nPortion, aPosInPara, bSmart ); - return aPaM; - } - } - - // Nicht gefunden - Dann den letzten sichtbare... - sal_uLong nLastNode = mpDoc->GetNodes().Count() - 1; - TextNode* pLast = mpDoc->GetNodes().GetObject( nLastNode ); - return TextPaM( nLastNode, pLast->GetText().Len() ); -} - -sal_uInt16 TextEngine::ImpFindIndex( sal_uLong nPortion, const Point& rPosInPara, sal_Bool bSmart ) -{ - DBG_ASSERT( IsFormatted(), "GetPaM: Nicht formatiert" ); - TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPortion ); - - sal_uInt16 nCurIndex = 0; - - long nY = 0; - TextLine* pLine = 0; - sal_uInt16 nLine; - for ( nLine = 0; nLine < pPortion->GetLines().size(); nLine++ ) - { - TextLine* pTmpLine = pPortion->GetLines()[ nLine ]; - nY += mnCharHeight; - if ( nY > rPosInPara.Y() ) // das war 'se - { - pLine = pTmpLine; - break; // richtige Y-Position intressiert nicht - } - } - DBG_ASSERT( pLine, "ImpFindIndex: pLine ?" ); - - nCurIndex = GetCharPos( nPortion, nLine, rPosInPara.X(), bSmart ); - - if ( nCurIndex && ( nCurIndex == pLine->GetEnd() ) && - ( pLine != pPortion->GetLines().back() ) ) - { - uno::Reference < i18n::XBreakIterator > xBI = GetBreakIterator(); - sal_Int32 nCount = 1; - nCurIndex = (sal_uInt16)xBI->previousCharacters( pPortion->GetNode()->GetText(), nCurIndex, GetLocale(), i18n::CharacterIteratorMode::SKIPCELL, nCount, nCount ); - } - return nCurIndex; -} - -sal_uInt16 TextEngine::GetCharPos( sal_uLong nPortion, sal_uInt16 nLine, long nXPos, sal_Bool ) -{ - - TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPortion ); - TextLine* pLine = pPortion->GetLines()[ nLine ]; - - sal_uInt16 nCurIndex = pLine->GetStart(); - - long nTmpX = pLine->GetStartX(); - if ( nXPos <= nTmpX ) - return nCurIndex; - - for ( sal_uInt16 i = pLine->GetStartPortion(); i <= pLine->GetEndPortion(); i++ ) - { - TETextPortion* pTextPortion = pPortion->GetTextPortions()[ i ]; - nTmpX += pTextPortion->GetWidth(); - - if ( nTmpX > nXPos ) - { - if( pTextPortion->GetLen() > 1 ) - { - nTmpX -= pTextPortion->GetWidth(); // vor die Portion stellen - // Optimieren: Kein GetTextBreak, wenn feste Fontbreite... - Font aFont; - SeekCursor( nPortion, nCurIndex+1, aFont, NULL ); - mpRefDev->SetFont( aFont); - long nPosInPortion = nXPos-nTmpX; - if ( IsRightToLeft() != pTextPortion->IsRightToLeft() ) - nPosInPortion = pTextPortion->GetWidth() - nPosInPortion; - nCurIndex = mpRefDev->GetTextBreak( pPortion->GetNode()->GetText(), nPosInPortion, nCurIndex ); - // MT: GetTextBreak should assure that we are not withing a CTL cell... - } - return nCurIndex; - } - nCurIndex = nCurIndex + pTextPortion->GetLen(); - } - return nCurIndex; -} - - -sal_uLong TextEngine::GetTextHeight() const -{ - DBG_ASSERT( GetUpdateMode(), "Sollte bei Update=sal_False nicht verwendet werden: GetTextHeight" ); - - if ( !IsFormatted() && !IsFormatting() ) - ((TextEngine*)this)->FormatAndUpdate(); - - return mnCurTextHeight; -} - -sal_uLong TextEngine::GetTextHeight( sal_uLong nParagraph ) const -{ - DBG_ASSERT( GetUpdateMode(), "Sollte bei Update=sal_False nicht verwendet werden: GetTextHeight" ); - - if ( !IsFormatted() && !IsFormatting() ) - ((TextEngine*)this)->FormatAndUpdate(); - - return CalcParaHeight( nParagraph ); -} - -sal_uLong TextEngine::CalcTextWidth( sal_uLong nPara ) -{ - sal_uLong nParaWidth = 0; - TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPara ); - for ( sal_uInt16 nLine = pPortion->GetLines().size(); nLine; ) - { - sal_uLong nLineWidth = 0; - TextLine* pLine = pPortion->GetLines()[ --nLine ]; - for ( sal_uInt16 nTP = pLine->GetStartPortion(); nTP <= pLine->GetEndPortion(); nTP++ ) - { - TETextPortion* pTextPortion = pPortion->GetTextPortions()[ nTP ]; - nLineWidth += pTextPortion->GetWidth(); - } - if ( nLineWidth > nParaWidth ) - nParaWidth = nLineWidth; - } - return nParaWidth; -} - -sal_uLong TextEngine::CalcTextWidth() -{ - if ( !IsFormatted() && !IsFormatting() ) - FormatAndUpdate(); - - if ( mnCurTextWidth == 0xFFFFFFFF ) - { - mnCurTextWidth = 0; - for ( sal_uLong nPara = mpTEParaPortions->Count(); nPara; ) - { - sal_uLong nParaWidth = CalcTextWidth( --nPara ); - if ( nParaWidth > mnCurTextWidth ) - mnCurTextWidth = nParaWidth; - } - } - return mnCurTextWidth+1;// Ein breiter, da in CreateLines bei >= umgebrochen wird. -} - -sal_uLong TextEngine::CalcTextHeight() -{ - DBG_ASSERT( GetUpdateMode(), "Sollte bei Update=sal_False nicht verwendet werden: CalcTextHeight" ); - - sal_uLong nY = 0; - for ( sal_uLong nPortion = mpTEParaPortions->Count(); nPortion; ) - nY += CalcParaHeight( --nPortion ); - return nY; -} - -sal_uLong TextEngine::CalcTextWidth( sal_uLong nPara, sal_uInt16 nPortionStart, sal_uInt16 nLen, const Font* pFont ) -{ - // Innerhalb des Textes darf es keinen Portionwechsel (Attribut/Tab) geben! - DBG_ASSERT( mpDoc->GetNodes().GetObject( nPara )->GetText().Search( '\t', nPortionStart ) >= (nPortionStart+nLen), "CalcTextWidth: Tab!" ); - - sal_uLong nWidth; - if ( mnFixCharWidth100 ) - { - nWidth = (sal_uLong)nLen*mnFixCharWidth100/100; - } - else - { - if ( pFont ) - { - if ( !mpRefDev->GetFont().IsSameInstance( *pFont ) ) - mpRefDev->SetFont( *pFont ); - } - else - { - Font aFont; - SeekCursor( nPara, nPortionStart+1, aFont, NULL ); - mpRefDev->SetFont( aFont ); - } - TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); - nWidth = (sal_uLong)mpRefDev->GetTextWidth( pNode->GetText(), nPortionStart, nLen ); - - } - return nWidth; -} - - -sal_uInt16 TextEngine::GetLineCount( sal_uLong nParagraph ) const -{ - DBG_ASSERT( nParagraph < mpTEParaPortions->Count(), "GetLineCount: Out of range" ); - - TEParaPortion* pPPortion = mpTEParaPortions->GetObject( nParagraph ); - if ( pPPortion ) - return pPPortion->GetLines().size(); - - return 0xFFFF; -} - -sal_uInt16 TextEngine::GetLineLen( sal_uLong nParagraph, sal_uInt16 nLine ) const -{ - DBG_ASSERT( nParagraph < mpTEParaPortions->Count(), "GetLineCount: Out of range" ); - - TEParaPortion* pPPortion = mpTEParaPortions->GetObject( nParagraph ); - if ( pPPortion && ( nLine < pPPortion->GetLines().size() ) ) - { - TextLine* pLine = pPPortion->GetLines()[ nLine ]; - return pLine->GetLen(); - } - - return 0xFFFF; -} - -sal_uLong TextEngine::CalcParaHeight( sal_uLong nParagraph ) const -{ - sal_uLong nHeight = 0; - - TEParaPortion* pPPortion = mpTEParaPortions->GetObject( nParagraph ); - DBG_ASSERT( pPPortion, "Absatz nicht gefunden: GetParaHeight" ); - if ( pPPortion ) - nHeight = pPPortion->GetLines().size() * mnCharHeight; - - return nHeight; -} - -void TextEngine::UpdateSelections() -{ -} - -Range TextEngine::GetInvalidYOffsets( sal_uLong nPortion ) -{ - TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPortion ); - sal_uInt16 nLines = pTEParaPortion->GetLines().size(); - sal_uInt16 nLastInvalid, nFirstInvalid = 0; - sal_uInt16 nLine; - for ( nLine = 0; nLine < nLines; nLine++ ) - { - TextLine* pL = pTEParaPortion->GetLines()[ nLine ]; - if ( pL->IsInvalid() ) - { - nFirstInvalid = nLine; - break; - } - } - - for ( nLastInvalid = nFirstInvalid; nLastInvalid < nLines; nLastInvalid++ ) - { - TextLine* pL = pTEParaPortion->GetLines()[ nLine ]; - if ( pL->IsValid() ) - break; - } - - if ( nLastInvalid >= nLines ) - nLastInvalid = nLines-1; - - return Range( nFirstInvalid*mnCharHeight, ((nLastInvalid+1)*mnCharHeight)-1 ); -} - -sal_uLong TextEngine::GetParagraphCount() const -{ - return mpDoc->GetNodes().Count(); -} - -void TextEngine::EnableUndo( sal_Bool bEnable ) -{ - // Beim Umschalten des Modus Liste loeschen: - if ( bEnable != IsUndoEnabled() ) - ResetUndo(); - - mbUndoEnabled = bEnable; -} - -::svl::IUndoManager& TextEngine::GetUndoManager() -{ - if ( !mpUndoManager ) - mpUndoManager = new TextUndoManager( this ); - return *mpUndoManager; -} - -void TextEngine::UndoActionStart( sal_uInt16 nId ) -{ - if ( IsUndoEnabled() && !IsInUndo() ) - { - String aComment; - // ... - GetUndoManager().EnterListAction( aComment, XubString(), nId ); - } -} - -void TextEngine::UndoActionEnd() -{ - if ( IsUndoEnabled() && !IsInUndo() ) - GetUndoManager().LeaveListAction(); -} - -void TextEngine::InsertUndo( TextUndo* pUndo, sal_Bool bTryMerge ) -{ - DBG_ASSERT( !IsInUndo(), "InsertUndo im Undomodus!" ); - GetUndoManager().AddUndoAction( pUndo, bTryMerge ); -} - -void TextEngine::ResetUndo() -{ - if ( mpUndoManager ) - mpUndoManager->Clear(); -} - -void TextEngine::InsertContent( TextNode* pNode, sal_uLong nPara ) -{ - DBG_ASSERT( pNode, "NULL-Pointer in InsertContent! " ); - DBG_ASSERT( IsInUndo(), "InsertContent nur fuer Undo()!" ); - TEParaPortion* pNew = new TEParaPortion( pNode ); - mpTEParaPortions->Insert( pNew, nPara ); - mpDoc->GetNodes().Insert( pNode, nPara ); - ImpParagraphInserted( nPara ); -} - -TextPaM TextEngine::SplitContent( sal_uLong nNode, sal_uInt16 nSepPos ) -{ - #ifdef DBG_UTIL - TextNode* pNode = mpDoc->GetNodes().GetObject( nNode ); - DBG_ASSERT( pNode, "Ungueltiger Node in SplitContent" ); - DBG_ASSERT( IsInUndo(), "SplitContent nur fuer Undo()!" ); - DBG_ASSERT( nSepPos <= pNode->GetText().Len(), "Index im Wald: SplitContent" ); - #endif - TextPaM aPaM( nNode, nSepPos ); - return ImpInsertParaBreak( aPaM ); -} - -TextPaM TextEngine::ConnectContents( sal_uLong nLeftNode ) -{ - DBG_ASSERT( IsInUndo(), "ConnectContent nur fuer Undo()!" ); - return ImpConnectParagraphs( nLeftNode, nLeftNode+1 ); -} - -void TextEngine::SeekCursor( sal_uLong nPara, sal_uInt16 nPos, Font& rFont, OutputDevice* pOutDev ) -{ - rFont = maFont; - if ( pOutDev ) - pOutDev->SetTextColor( maTextColor ); - - TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); - sal_uInt16 nAttribs = pNode->GetCharAttribs().Count(); - for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ ) - { - TextCharAttrib* pAttrib = pNode->GetCharAttribs().GetAttrib( nAttr ); - if ( pAttrib->GetStart() > nPos ) - break; - - // Beim Seeken nicht die Attr beruecksichtigen, die dort beginnen! - // Leere Attribute werden beruecksichtigt( verwendet), da diese - // gerade eingestellt wurden. - // 12.4.95: Doch keine Leeren Attribute verwenden: - // - Wenn gerade eingestellt und leer => keine Auswirkung auf Font - // In einem leeren Absatz eingestellte Zeichen werden sofort wirksam. - if ( ( ( pAttrib->GetStart() < nPos ) && ( pAttrib->GetEnd() >= nPos ) ) - || !pNode->GetText().Len() ) - { - if ( pAttrib->Which() != TEXTATTR_FONTCOLOR ) - { - pAttrib->GetAttr().SetFont(rFont); - } - else - { - if ( pOutDev ) - pOutDev->SetTextColor( ((TextAttribFontColor&)pAttrib->GetAttr()).GetColor() ); - } - } - } - - if ( mpIMEInfos && mpIMEInfos->pAttribs && ( mpIMEInfos->aPos.GetPara() == nPara ) && - ( nPos > mpIMEInfos->aPos.GetIndex() ) && ( nPos <= ( mpIMEInfos->aPos.GetIndex() + mpIMEInfos->nLen ) ) ) - { - sal_uInt16 nAttr = mpIMEInfos->pAttribs[ nPos - mpIMEInfos->aPos.GetIndex() - 1 ]; - if ( nAttr & EXTTEXTINPUT_ATTR_UNDERLINE ) - rFont.SetUnderline( UNDERLINE_SINGLE ); - else if ( nAttr & EXTTEXTINPUT_ATTR_BOLDUNDERLINE ) - rFont.SetUnderline( UNDERLINE_BOLD ); - else if ( nAttr & EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE ) - rFont.SetUnderline( UNDERLINE_DOTTED ); - else if ( nAttr & EXTTEXTINPUT_ATTR_DASHDOTUNDERLINE ) - rFont.SetUnderline( UNDERLINE_DOTTED ); - if ( nAttr & EXTTEXTINPUT_ATTR_REDTEXT ) - rFont.SetColor( Color( COL_RED ) ); - else if ( nAttr & EXTTEXTINPUT_ATTR_HALFTONETEXT ) - rFont.SetColor( Color( COL_LIGHTGRAY ) ); - if ( nAttr & EXTTEXTINPUT_ATTR_HIGHLIGHT ) - { - const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); - rFont.SetColor( rStyleSettings.GetHighlightTextColor() ); - rFont.SetFillColor( rStyleSettings.GetHighlightColor() ); - rFont.SetTransparent( sal_False ); - } - else if ( nAttr & EXTTEXTINPUT_ATTR_GRAYWAVELINE ) - { - rFont.SetUnderline( UNDERLINE_WAVE ); -// if( pOut ) -// pOut->SetTextLineColor( Color( COL_LIGHTGRAY ) ); - } - } -} - -void TextEngine::FormatAndUpdate( TextView* pCurView ) -{ - if ( mbDowning ) - return ; - - if ( IsInUndo() ) - IdleFormatAndUpdate( pCurView ); - else - { - FormatDoc(); - UpdateViews( pCurView ); - } -} - - -void TextEngine::IdleFormatAndUpdate( TextView* pCurView, sal_uInt16 nMaxTimerRestarts ) -{ - mpIdleFormatter->DoIdleFormat( pCurView, nMaxTimerRestarts ); -} - -void TextEngine::TextModified() -{ - mbFormatted = sal_False; - mbModified = sal_True; -} - -void TextEngine::UpdateViews( TextView* pCurView ) -{ - if ( !GetUpdateMode() || IsFormatting() || maInvalidRec.IsEmpty() ) - return; - - DBG_ASSERT( IsFormatted(), "UpdateViews: Doc nicht formatiert!" ); - - for ( sal_uInt16 nView = 0; nView < mpViews->size(); nView++ ) - { - TextView* pView = (*mpViews)[ nView ]; - pView->HideCursor(); - - Rectangle aClipRec( maInvalidRec ); - Size aOutSz = pView->GetWindow()->GetOutputSizePixel(); - Rectangle aVisArea( pView->GetStartDocPos(), aOutSz ); - aClipRec.Intersection( aVisArea ); - if ( !aClipRec.IsEmpty() ) - { - // in Fensterkoordinaten umwandeln.... - Point aNewPos = pView->GetWindowPos( aClipRec.TopLeft() ); - if ( IsRightToLeft() ) - aNewPos.X() -= aOutSz.Width() - 1; - aClipRec.SetPos( aNewPos ); - - if ( pView == pCurView ) - pView->ImpPaint( aClipRec, !pView->GetWindow()->IsPaintTransparent() ); - else - pView->GetWindow()->Invalidate( aClipRec ); - } - } - - if ( pCurView ) - { - pCurView->ShowCursor( pCurView->IsAutoScroll() ); - } - - maInvalidRec = Rectangle(); -} - -IMPL_LINK_NOARG(TextEngine, IdleFormatHdl) -{ - FormatAndUpdate( mpIdleFormatter->GetView() ); - return 0; -} - -void TextEngine::CheckIdleFormatter() -{ - mpIdleFormatter->ForceTimeout(); -} - -void TextEngine::FormatFullDoc() -{ - for ( sal_uLong nPortion = 0; nPortion < mpTEParaPortions->Count(); nPortion++ ) - { - TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPortion ); sal_uInt16 nLen = pTEParaPortion->GetNode()->GetText().Len(); - pTEParaPortion->MarkSelectionInvalid( 0, nLen ); - } - mbFormatted = sal_False; - FormatDoc(); -} - -void TextEngine::FormatDoc() -{ - if ( IsFormatted() || !GetUpdateMode() || IsFormatting() ) - return; - - mbIsFormatting = sal_True; - mbHasMultiLineParas = sal_False; - - long nY = 0; - sal_Bool bGrow = sal_False; - - maInvalidRec = Rectangle(); // leermachen - for ( sal_uLong nPara = 0; nPara < mpTEParaPortions->Count(); nPara++ ) - { - TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); - if ( pTEParaPortion->IsInvalid() ) - { - sal_uLong nOldParaWidth = 0xFFFFFFFF; - if ( mnCurTextWidth != 0xFFFFFFFF ) - nOldParaWidth = CalcTextWidth( nPara ); - - ImpFormattingParagraph( nPara ); - - if ( CreateLines( nPara ) ) - bGrow = sal_True; - - // InvalidRec nur einmal setzen... - if ( maInvalidRec.IsEmpty() ) - { - // Bei Paperwidth 0 (AutoPageSize) bleibt es sonst Empty()... - long nWidth = (long)mnMaxTextWidth; - if ( !nWidth ) - nWidth = 0x7FFFFFFF; - Range aInvRange( GetInvalidYOffsets( nPara ) ); - maInvalidRec = Rectangle( Point( 0, nY+aInvRange.Min() ), - Size( nWidth, aInvRange.Len() ) ); - } - else - { - maInvalidRec.Bottom() = nY + CalcParaHeight( nPara ); - } - - if ( mnCurTextWidth != 0xFFFFFFFF ) - { - sal_uLong nNewParaWidth = CalcTextWidth( nPara ); - if ( nNewParaWidth >= mnCurTextWidth ) - mnCurTextWidth = nNewParaWidth; - else if ( ( nOldParaWidth != 0xFFFFFFFF ) && ( nOldParaWidth >= mnCurTextWidth ) ) - mnCurTextWidth = 0xFFFFFFFF; - } - } - else if ( bGrow ) - { - maInvalidRec.Bottom() = nY + CalcParaHeight( nPara ); - } - nY += CalcParaHeight( nPara ); - if ( !mbHasMultiLineParas && pTEParaPortion->GetLines().size() > 1 ) - mbHasMultiLineParas = sal_True; - } - - if ( !maInvalidRec.IsEmpty() ) - { - sal_uLong nNewHeight = CalcTextHeight(); - long nDiff = nNewHeight - mnCurTextHeight; - if ( nNewHeight < mnCurTextHeight ) - { - maInvalidRec.Bottom() = (long)Max( nNewHeight, mnCurTextHeight ); - if ( maInvalidRec.IsEmpty() ) - { - maInvalidRec.Top() = 0; - // Left und Right werden nicht ausgewertet, aber wegen IsEmpty gesetzt. - maInvalidRec.Left() = 0; - maInvalidRec.Right() = mnMaxTextWidth; - } - } - - mnCurTextHeight = nNewHeight; - if ( nDiff ) - { - mbFormatted = sal_True; - ImpTextHeightChanged(); - } - } - - mbIsFormatting = sal_False; - mbFormatted = sal_True; - - ImpTextFormatted(); -} - -void TextEngine::CreateAndInsertEmptyLine( sal_uLong nPara ) -{ - TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); - TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); - - TextLine* pTmpLine = new TextLine; - pTmpLine->SetStart( pNode->GetText().Len() ); - pTmpLine->SetEnd( pTmpLine->GetStart() ); - pTEParaPortion->GetLines().push_back( pTmpLine ); - - if ( ImpGetAlign() == TXTALIGN_CENTER ) - pTmpLine->SetStartX( (short)(mnMaxTextWidth / 2) ); - else if ( ImpGetAlign() == TXTALIGN_RIGHT ) - pTmpLine->SetStartX( (short)mnMaxTextWidth ); - else - pTmpLine->SetStartX( mpDoc->GetLeftMargin() ); - - sal_Bool bLineBreak = pNode->GetText().Len() ? sal_True : sal_False; - - TETextPortion* pDummyPortion = new TETextPortion( 0 ); - pDummyPortion->GetWidth() = 0; - pTEParaPortion->GetTextPortions().push_back( pDummyPortion ); - - if ( bLineBreak == sal_True ) - { - // -2: The new one is already inserted. - OSL_ENSURE( - pTEParaPortion->GetLines()[pTEParaPortion->GetLines().size()-2], - "Soft Break, no Line?!"); - sal_uInt16 nPos = (sal_uInt16) pTEParaPortion->GetTextPortions().size() - 1 ; - pTmpLine->SetStartPortion( nPos ); - pTmpLine->SetEndPortion( nPos ); - } -} - -void TextEngine::ImpBreakLine( sal_uLong nPara, TextLine* pLine, TETextPortion*, sal_uInt16 nPortionStart, long nRemainingWidth ) -{ - TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); - - // Font sollte noch eingestellt sein. - sal_uInt16 nMaxBreakPos = mpRefDev->GetTextBreak( pNode->GetText(), nRemainingWidth, nPortionStart ); - - DBG_ASSERT( nMaxBreakPos < pNode->GetText().Len(), "Break?!" ); - - if ( nMaxBreakPos == STRING_LEN ) // GetTextBreak() ist anderer Auffassung als GetTextSize() - nMaxBreakPos = pNode->GetText().Len() - 1; - - uno::Reference < i18n::XBreakIterator > xBI = GetBreakIterator(); - i18n::LineBreakHyphenationOptions aHyphOptions( NULL, uno::Sequence< beans::PropertyValue >(), 1 ); - - i18n::LineBreakUserOptions aUserOptions; - aUserOptions.forbiddenBeginCharacters = ImpGetLocaleDataWrapper()->getForbiddenCharacters().beginLine; - aUserOptions.forbiddenEndCharacters = ImpGetLocaleDataWrapper()->getForbiddenCharacters().endLine; - aUserOptions.applyForbiddenRules = sal_True; - aUserOptions.allowPunctuationOutsideMargin = sal_False; - aUserOptions.allowHyphenateEnglish = sal_False; - - static const com::sun::star::lang::Locale aDefLocale; - i18n::LineBreakResults aLBR = xBI->getLineBreak( pNode->GetText(), nMaxBreakPos, aDefLocale, pLine->GetStart(), aHyphOptions, aUserOptions ); - sal_uInt16 nBreakPos = (sal_uInt16)aLBR.breakIndex; - if ( nBreakPos <= pLine->GetStart() ) - { - nBreakPos = nMaxBreakPos; - if ( nBreakPos <= pLine->GetStart() ) - nBreakPos = pLine->GetStart() + 1; // Sonst Endlosschleife! - } - - - // die angeknackste Portion ist die End-Portion - pLine->SetEnd( nBreakPos ); - sal_uInt16 nEndPortion = SplitTextPortion( nPara, nBreakPos ); - - sal_Bool bBlankSeparator = ( ( nBreakPos >= pLine->GetStart() ) && - ( pNode->GetText().GetChar( nBreakPos ) == ' ' ) ) ? sal_True : sal_False; - if ( bBlankSeparator ) - { - // Blanks am Zeilenende generell unterdruecken... - TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); - TETextPortion* pTP = pTEParaPortion->GetTextPortions()[ nEndPortion ]; - DBG_ASSERT( nBreakPos > pLine->GetStart(), "SplitTextPortion am Anfang der Zeile?" ); - pTP->GetWidth() = (long)CalcTextWidth( nPara, nBreakPos-pTP->GetLen(), pTP->GetLen()-1 ); - } - pLine->SetEndPortion( nEndPortion ); -} - -sal_uInt16 TextEngine::SplitTextPortion( sal_uLong nPara, sal_uInt16 nPos ) -{ - - // Die Portion bei nPos wird geplittet, wenn bei nPos nicht - // sowieso ein Wechsel ist - if ( nPos == 0 ) - return 0; - - sal_uInt16 nSplitPortion; - sal_uInt16 nTmpPos = 0; - TETextPortion* pTextPortion = 0; - TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); - sal_uInt16 nPortions = pTEParaPortion->GetTextPortions().size(); - for ( nSplitPortion = 0; nSplitPortion < nPortions; nSplitPortion++ ) - { - TETextPortion* pTP = pTEParaPortion->GetTextPortions()[nSplitPortion]; - nTmpPos = nTmpPos + pTP->GetLen(); - if ( nTmpPos >= nPos ) - { - if ( nTmpPos == nPos ) // dann braucht nichts geteilt werden - return nSplitPortion; - pTextPortion = pTP; - break; - } - } - - DBG_ASSERT( pTextPortion, "Position ausserhalb des Bereichs!" ); - - sal_uInt16 nOverlapp = nTmpPos - nPos; - pTextPortion->GetLen() = pTextPortion->GetLen() - nOverlapp; - TETextPortion* pNewPortion = new TETextPortion( nOverlapp ); - pTEParaPortion->GetTextPortions().insert( pTEParaPortion->GetTextPortions().begin() + nSplitPortion + 1, pNewPortion ); - pTextPortion->GetWidth() = (long)CalcTextWidth( nPara, nPos-pTextPortion->GetLen(), pTextPortion->GetLen() ); - - return nSplitPortion; -} - -void TextEngine::CreateTextPortions( sal_uLong nPara, sal_uInt16 nStartPos ) -{ - TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); - TextNode* pNode = pTEParaPortion->GetNode(); - DBG_ASSERT( pNode->GetText().Len(), "CreateTextPortions sollte nicht fuer leere Absaetze verwendet werden!" ); - - std::set aPositions; - std::set::iterator aPositionsIt; - aPositions.insert(0); - - sal_uInt16 nAttribs = pNode->GetCharAttribs().Count(); - for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ ) - { - TextCharAttrib* pAttrib = pNode->GetCharAttribs().GetAttrib( nAttr ); - - aPositions.insert( pAttrib->GetStart() ); - aPositions.insert( pAttrib->GetEnd() ); - } - aPositions.insert( pNode->GetText().Len() ); - - const std::vector& rWritingDirections = pTEParaPortion->GetWritingDirectionInfos(); - for ( std::vector::const_iterator it = rWritingDirections.begin(); it != rWritingDirections.end(); ++it ) - aPositions.insert( (*it).nStartPos ); - - if ( mpIMEInfos && mpIMEInfos->pAttribs && ( mpIMEInfos->aPos.GetPara() == nPara ) ) - { - sal_uInt16 nLastAttr = 0xFFFF; - for( sal_uInt16 n = 0; n < mpIMEInfos->nLen; n++ ) - { - if ( mpIMEInfos->pAttribs[n] != nLastAttr ) - { - aPositions.insert( mpIMEInfos->aPos.GetIndex() + n ); - nLastAttr = mpIMEInfos->pAttribs[n]; - } - } - } - - sal_uInt16 nTabPos = pNode->GetText().Search( '\t', 0 ); - while ( nTabPos != STRING_NOTFOUND ) - { - aPositions.insert( nTabPos ); - aPositions.insert( nTabPos + 1 ); - nTabPos = pNode->GetText().Search( '\t', nTabPos+1 ); - } - - // Ab ... loeschen: - // Leider muss die Anzahl der TextPortions mit aPositions.Count() - // nicht uebereinstimmen, da evtl. Zeilenumbrueche... - sal_uInt16 nPortionStart = 0; - sal_uInt16 nInvPortion = 0; - sal_uInt16 nP; - for ( nP = 0; nP < pTEParaPortion->GetTextPortions().size(); nP++ ) - { - TETextPortion* pTmpPortion = pTEParaPortion->GetTextPortions()[nP]; - nPortionStart = nPortionStart + pTmpPortion->GetLen(); - if ( nPortionStart >= nStartPos ) - { - nPortionStart = nPortionStart - pTmpPortion->GetLen(); - nInvPortion = nP; - break; - } - } - OSL_ENSURE(nP < pTEParaPortion->GetTextPortions().size() - || pTEParaPortion->GetTextPortions().empty(), - "Nothing to delete: CreateTextPortions"); - if ( nInvPortion && ( nPortionStart+pTEParaPortion->GetTextPortions()[nInvPortion]->GetLen() > nStartPos ) ) - { - // lieber eine davor... - // Aber nur wenn es mitten in der Portion war, sonst ist es evtl. - // die einzige in der Zeile davor ! - nInvPortion--; - nPortionStart = nPortionStart - pTEParaPortion->GetTextPortions()[nInvPortion]->GetLen(); - } - pTEParaPortion->GetTextPortions().DeleteFromPortion( nInvPortion ); - - // Eine Portion kann auch durch einen Zeilenumbruch entstanden sein: - aPositions.insert( nPortionStart ); - - aPositionsIt = aPositions.find( nPortionStart ); - DBG_ASSERT( aPositionsIt != aPositions.end(), "nPortionStart not found" ); - - if ( aPositionsIt != aPositions.end() ) - { - std::set::iterator nextIt = aPositionsIt; - for ( ++nextIt; nextIt != aPositions.end(); ++aPositionsIt, ++nextIt ) - { - TETextPortion* pNew = new TETextPortion( *nextIt - *aPositionsIt ); - pTEParaPortion->GetTextPortions().push_back( pNew ); - } - } - OSL_ENSURE(pTEParaPortion->GetTextPortions().size(), "No Portions?!"); -} - -void TextEngine::RecalcTextPortion( sal_uLong nPara, sal_uInt16 nStartPos, short nNewChars ) -{ - TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); - OSL_ENSURE(pTEParaPortion->GetTextPortions().size(), "no Portions!"); - OSL_ENSURE(nNewChars, "RecalcTextPortion with Diff == 0"); - - TextNode* const pNode = pTEParaPortion->GetNode(); - if ( nNewChars > 0 ) - { - // Wenn an nStartPos ein Attribut beginnt/endet, oder vor nStartPos - // ein Tab steht, faengt eine neue Portion an, - // ansonsten wird die Portion an nStartPos erweitert. - // Oder wenn ganz vorne ( StartPos 0 ) und dann ein Tab - - if ( ( pNode->GetCharAttribs().HasBoundingAttrib( nStartPos ) ) || - ( nStartPos && ( pNode->GetText().GetChar( nStartPos - 1 ) == '\t' ) ) || - ( ( !nStartPos && ( nNewChars < pNode->GetText().Len() ) && pNode->GetText().GetChar( nNewChars ) == '\t' ) ) ) - { - sal_uInt16 nNewPortionPos = 0; - if ( nStartPos ) - nNewPortionPos = SplitTextPortion( nPara, nStartPos ) + 1; - - // Eine leere Portion kann hier stehen, wenn der Absatz leer war, - // oder eine Zeile durch einen harten Zeilenumbruch entstanden ist. - if ( ( nNewPortionPos < pTEParaPortion->GetTextPortions().size() ) && - !pTEParaPortion->GetTextPortions()[nNewPortionPos]->GetLen() ) - { - // Dann die leere Portion verwenden. - sal_uInt16 & r = - pTEParaPortion->GetTextPortions()[nNewPortionPos]->GetLen(); - r = r + nNewChars; - } - else - { - TETextPortion* pNewPortion = new TETextPortion( nNewChars ); - pTEParaPortion->GetTextPortions().insert( pTEParaPortion->GetTextPortions().begin() + nNewPortionPos, pNewPortion ); - } - } - else - { - sal_uInt16 nPortionStart; - const sal_uInt16 nTP = pTEParaPortion->GetTextPortions(). - FindPortion( nStartPos, nPortionStart ); - TETextPortion* const pTP = pTEParaPortion->GetTextPortions()[ nTP ]; - DBG_ASSERT( pTP, "RecalcTextPortion: Portion nicht gefunden" ); - pTP->GetLen() = pTP->GetLen() + nNewChars; - pTP->GetWidth() = (-1); - } - } - else - { - // Portion schrumpfen oder ggf. entfernen. - // Vor Aufruf dieser Methode muss sichergestellt sein, dass - // keine Portions in dem geloeschten Bereich lagen! - - // Es darf keine reinragende oder im Bereich startende Portion geben, - // also muss nStartPos <= nPos <= nStartPos - nNewChars(neg.) sein - sal_uInt16 nPortion = 0; - sal_uInt16 nPos = 0; - sal_uInt16 nEnd = nStartPos-nNewChars; - sal_uInt16 nPortions = pTEParaPortion->GetTextPortions().size(); - TETextPortion* pTP = 0; - for ( nPortion = 0; nPortion < nPortions; nPortion++ ) - { - pTP = pTEParaPortion->GetTextPortions()[ nPortion ]; - if ( ( nPos+pTP->GetLen() ) > nStartPos ) - { - DBG_ASSERT( nPos <= nStartPos, "Start falsch!" ); - DBG_ASSERT( nPos+pTP->GetLen() >= nEnd, "End falsch!" ); - break; - } - nPos = nPos + pTP->GetLen(); - } - DBG_ASSERT( pTP, "RecalcTextPortion: Portion nicht gefunden" ); - if ( ( nPos == nStartPos ) && ( (nPos+pTP->GetLen()) == nEnd ) ) - { - // Portion entfernen; - pTEParaPortion->GetTextPortions().erase( pTEParaPortion->GetTextPortions().begin() + nPortion ); - delete pTP; - } - else - { - DBG_ASSERT( pTP->GetLen() > (-nNewChars), "Portion zu klein zum schrumpfen!" ); - pTP->GetLen() = pTP->GetLen() + nNewChars; - } - OSL_ENSURE( pTEParaPortion->GetTextPortions().size(), - "RecalcTextPortions: none are left!" ); - } -} - -void TextEngine::ImpPaint( OutputDevice* pOutDev, const Point& rStartPos, Rectangle const* pPaintArea, TextSelection const* pPaintRange, TextSelection const* pSelection ) -{ - if ( !GetUpdateMode() ) - return; - - if ( !IsFormatted() ) - FormatDoc(); - - bool bTransparent = false; - Window* pOutWin = dynamic_cast(pOutDev); - bTransparent = (pOutWin && pOutWin->IsPaintTransparent()); - - long nY = rStartPos.Y(); - - TextPaM const* pSelStart = 0; - TextPaM const* pSelEnd = 0; - if ( pSelection && pSelection->HasRange() ) - { - sal_Bool bInvers = pSelection->GetEnd() < pSelection->GetStart(); - pSelStart = !bInvers ? &pSelection->GetStart() : &pSelection->GetEnd(); - pSelEnd = bInvers ? &pSelection->GetStart() : &pSelection->GetEnd(); - } - DBG_ASSERT( !pPaintRange || ( pPaintRange->GetStart() < pPaintRange->GetEnd() ), "ImpPaint: Paint-Range?!" ); - - const StyleSettings& rStyleSettings = pOutDev->GetSettings().GetStyleSettings(); - - // -------------------------------------------------- - // Ueber alle Absaetze... - // -------------------------------------------------- - for ( sal_uLong nPara = 0; nPara < mpTEParaPortions->Count(); nPara++ ) - { - TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPara ); - // falls beim Tippen Idle-Formatierung, asynchrones Paint. - if ( pPortion->IsInvalid() ) - return; - - sal_uLong nParaHeight = CalcParaHeight( nPara ); - if ( ( !pPaintArea || ( ( nY + (long)nParaHeight ) > pPaintArea->Top() ) ) - && ( !pPaintRange || ( ( nPara >= pPaintRange->GetStart().GetPara() ) && ( nPara <= pPaintRange->GetEnd().GetPara() ) ) ) ) - { - // -------------------------------------------------- - // Ueber die Zeilen des Absatzes... - // -------------------------------------------------- - sal_uInt16 nLines = pPortion->GetLines().size(); - sal_uInt16 nIndex = 0; - for ( sal_uInt16 nLine = 0; nLine < nLines; nLine++ ) - { - TextLine* pLine = pPortion->GetLines()[nLine]; - Point aTmpPos( rStartPos.X() + pLine->GetStartX(), nY ); - - if ( ( !pPaintArea || ( ( nY + mnCharHeight ) > pPaintArea->Top() ) ) - && ( !pPaintRange || ( - ( TextPaM( nPara, pLine->GetStart() ) < pPaintRange->GetEnd() ) && - ( TextPaM( nPara, pLine->GetEnd() ) > pPaintRange->GetStart() ) ) ) ) - { - // -------------------------------------------------- - // Ueber die Portions der Zeile... - // -------------------------------------------------- - nIndex = pLine->GetStart(); - for ( sal_uInt16 y = pLine->GetStartPortion(); y <= pLine->GetEndPortion(); y++ ) - { - OSL_ENSURE(pPortion->GetTextPortions().size(), - "Line without Textportion in Paint!"); - TETextPortion* pTextPortion = pPortion->GetTextPortions()[ y ]; - DBG_ASSERT( pTextPortion, "NULL-Pointer im Portioniterator in UpdateViews" ); - - ImpInitLayoutMode( pOutDev /*, pTextPortion->IsRightToLeft() */); - - long nTxtWidth = pTextPortion->GetWidth(); - aTmpPos.X() = rStartPos.X() + ImpGetOutputOffset( nPara, pLine, nIndex, nIndex ); - - // nur ausgeben, was im sichtbaren Bereich beginnt: - if ( ( ( aTmpPos.X() + nTxtWidth ) >= 0 ) - && ( !pPaintRange || ( - ( TextPaM( nPara, nIndex ) < pPaintRange->GetEnd() ) && - ( TextPaM( nPara, nIndex + pTextPortion->GetLen() ) > pPaintRange->GetStart() ) ) ) ) - { - switch ( pTextPortion->GetKind() ) - { - case PORTIONKIND_TEXT: - { - { - Font aFont; - SeekCursor( nPara, nIndex+1, aFont, pOutDev ); - if( bTransparent ) - aFont.SetTransparent( sal_True ); - else if ( pSelection ) - aFont.SetTransparent( sal_False ); - pOutDev->SetFont( aFont ); - - sal_uInt16 nTmpIndex = nIndex; - sal_uInt16 nEnd = nTmpIndex + pTextPortion->GetLen(); - Point aPos = aTmpPos; - if ( pPaintRange ) - { - // evtl soll nicht alles ausgegeben werden... - if ( ( pPaintRange->GetStart().GetPara() == nPara ) - && ( nTmpIndex < pPaintRange->GetStart().GetIndex() ) ) - { - nTmpIndex = pPaintRange->GetStart().GetIndex(); - } - if ( ( pPaintRange->GetEnd().GetPara() == nPara ) - && ( nEnd > pPaintRange->GetEnd().GetIndex() ) ) - { - nEnd = pPaintRange->GetEnd().GetIndex(); - } - } - - sal_Bool bDone = sal_False; - if ( pSelStart ) - { - // liegt ein Teil in der Selektion??? - TextPaM aTextStart( nPara, nTmpIndex ); - TextPaM aTextEnd( nPara, nEnd ); - if ( ( aTextStart < *pSelEnd ) && ( aTextEnd > *pSelStart ) ) - { - sal_uInt16 nL; - - // 1) Bereich vor Selektion - if ( aTextStart < *pSelStart ) - { - nL = pSelStart->GetIndex() - nTmpIndex; - pOutDev->SetFont( aFont); - aPos.X() = rStartPos.X() + ImpGetOutputOffset( nPara, pLine, nTmpIndex, nTmpIndex+nL ); - pOutDev->DrawText( aPos, pPortion->GetNode()->GetText(), nTmpIndex, nL ); - nTmpIndex = nTmpIndex + nL; - - } - // 2) Bereich mit Selektion - nL = nEnd-nTmpIndex; - if ( aTextEnd > *pSelEnd ) - nL = pSelEnd->GetIndex() - nTmpIndex; - if ( nL ) - { - Color aOldTextColor = pOutDev->GetTextColor(); - pOutDev->SetTextColor( rStyleSettings.GetHighlightTextColor() ); - pOutDev->SetTextFillColor( rStyleSettings.GetHighlightColor() ); - aPos.X() = rStartPos.X() + ImpGetOutputOffset( nPara, pLine, nTmpIndex, nTmpIndex+nL ); - pOutDev->DrawText( aPos, pPortion->GetNode()->GetText(), nTmpIndex, nL ); - pOutDev->SetTextColor( aOldTextColor ); - pOutDev->SetTextFillColor(); - nTmpIndex = nTmpIndex + nL; - } - - // 3) Bereich nach Selektion - if ( nTmpIndex < nEnd ) - { - nL = nEnd-nTmpIndex; - aPos.X() = rStartPos.X() + ImpGetOutputOffset( nPara, pLine, nTmpIndex, nTmpIndex+nL ); - pOutDev->DrawText( aPos, pPortion->GetNode()->GetText(), nTmpIndex, nEnd-nTmpIndex ); - } - bDone = sal_True; - } - } - if ( !bDone ) - { - aPos.X() = rStartPos.X() + ImpGetOutputOffset( nPara, pLine, nTmpIndex, nEnd ); - pOutDev->DrawText( aPos, pPortion->GetNode()->GetText(), nTmpIndex, nEnd-nTmpIndex ); - } - } - - } - break; - case PORTIONKIND_TAB: - { - // Bei HideSelection() nur Range, pSelection = 0. - if ( pSelStart || pPaintRange ) - { - Rectangle aTabArea( aTmpPos, Point( aTmpPos.X()+nTxtWidth, aTmpPos.Y()+mnCharHeight-1 ) ); - sal_Bool bDone = sal_False; - if ( pSelStart ) - { - // liegt der Tab in der Selektion??? - TextPaM aTextStart( nPara, nIndex ); - TextPaM aTextEnd( nPara, nIndex+1 ); - if ( ( aTextStart < *pSelEnd ) && ( aTextEnd > *pSelStart ) ) - { - Color aOldColor = pOutDev->GetFillColor(); - pOutDev->SetFillColor( rStyleSettings.GetHighlightColor() ); - pOutDev->DrawRect( aTabArea ); - pOutDev->SetFillColor( aOldColor ); - bDone = sal_True; - } - } - if ( !bDone ) - { - pOutDev->Erase( aTabArea ); - } - } - } - break; - default: OSL_FAIL( "ImpPaint: Unknown Portion-Type !" ); - } - } - - nIndex = nIndex + pTextPortion->GetLen(); - } - } - - nY += mnCharHeight; - - if ( pPaintArea && ( nY >= pPaintArea->Bottom() ) ) - break; // keine sichtbaren Aktionen mehr... - } - } - else - { - nY += nParaHeight; - } - - if ( pPaintArea && ( nY > pPaintArea->Bottom() ) ) - break; // keine sichtbaren Aktionen mehr... - } -} - -sal_Bool TextEngine::CreateLines( sal_uLong nPara ) -{ - // sal_Bool: Aenderung der Hoehe des Absatzes Ja/Nein - sal_True/sal_False - - TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); - TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); - DBG_ASSERT( pTEParaPortion->IsInvalid(), "CreateLines: Portion nicht invalid!" ); - - sal_uInt16 nOldLineCount = pTEParaPortion->GetLines().size(); - - // --------------------------------------------------------------- - // Schnelle Sonderbehandlung fuer leere Absaetze... - // --------------------------------------------------------------- - if ( pTEParaPortion->GetNode()->GetText().Len() == 0 ) - { - // schnelle Sonderbehandlung... - if ( !pTEParaPortion->GetTextPortions().empty() ) - pTEParaPortion->GetTextPortions().Reset(); - if ( !pTEParaPortion->GetLines().empty() ) - { - BOOST_FOREACH(TextLine* pLine, pTEParaPortion->GetLines()) - delete pLine; - pTEParaPortion->GetLines().clear(); - } - CreateAndInsertEmptyLine( nPara ); - pTEParaPortion->SetValid(); - return nOldLineCount != pTEParaPortion->GetLines().size(); - } - - // --------------------------------------------------------------- - // Initialisierung...... - // --------------------------------------------------------------- - - if ( pTEParaPortion->GetLines().empty() ) - { - TextLine* pL = new TextLine; - pTEParaPortion->GetLines().push_back( pL ); - } - - const short nInvalidDiff = pTEParaPortion->GetInvalidDiff(); - const sal_uInt16 nInvalidStart = pTEParaPortion->GetInvalidPosStart(); - const sal_uInt16 nInvalidEnd = nInvalidStart + Abs( nInvalidDiff ); - sal_Bool bQuickFormat = sal_False; - - if ( pTEParaPortion->GetWritingDirectionInfos().empty() ) - ImpInitWritingDirections( nPara ); - - if ( pTEParaPortion->GetWritingDirectionInfos().size() == 1 ) - { - if ( pTEParaPortion->IsSimpleInvalid() && ( nInvalidDiff > 0 ) ) - { - bQuickFormat = sal_True; - } - else if ( ( pTEParaPortion->IsSimpleInvalid() ) && ( nInvalidDiff < 0 ) ) - { - // pruefen, ob loeschen ueber Portiongrenzen erfolgte... - sal_uInt16 nStart = nInvalidStart; // DOPPELT !!!!!!!!!!!!!!! - sal_uInt16 nEnd = nStart - nInvalidDiff; // neg. - bQuickFormat = sal_True; - sal_uInt16 nPos = 0; - sal_uInt16 nPortions = pTEParaPortion->GetTextPortions().size(); - for ( sal_uInt16 nTP = 0; nTP < nPortions; nTP++ ) - { - // Es darf kein Start/Ende im geloeschten Bereich liegen. - TETextPortion* const pTP = pTEParaPortion->GetTextPortions()[ nTP ]; - nPos = nPos + pTP->GetLen(); - if ( ( nPos > nStart ) && ( nPos < nEnd ) ) - { - bQuickFormat = sal_False; - break; - } - } - } - } - - if ( bQuickFormat ) - RecalcTextPortion( nPara, nInvalidStart, nInvalidDiff ); - else - CreateTextPortions( nPara, nInvalidStart ); - - // --------------------------------------------------------------- - // Zeile mit InvalidPos suchen, eine Zeile davor beginnen... - // Zeilen flaggen => nicht removen ! - // --------------------------------------------------------------- - - sal_uInt16 nLine = pTEParaPortion->GetLines().size()-1; - for ( sal_uInt16 nL = 0; nL <= nLine; nL++ ) - { - TextLine* pLine = pTEParaPortion->GetLines()[ nL ]; - if ( pLine->GetEnd() > nInvalidStart ) - { - nLine = nL; - break; - } - pLine->SetValid(); - } - // Eine Zeile davor beginnen... - // Wenn ganz hinten getippt wird, kann sich die Zeile davor nicht aendern. - if ( nLine && ( !pTEParaPortion->IsSimpleInvalid() || ( nInvalidEnd < pNode->GetText().Len() ) || ( nInvalidDiff <= 0 ) ) ) - nLine--; - - TextLine* pLine = pTEParaPortion->GetLines()[ nLine ]; - - // --------------------------------------------------------------- - // Ab hier alle Zeilen durchformatieren... - // --------------------------------------------------------------- - size_t nDelFromLine = std::numeric_limits::max(); - sal_Bool bLineBreak = sal_False; - - sal_uInt16 nIndex = pLine->GetStart(); - TextLine aSaveLine( *pLine ); - - Font aFont; - - sal_Bool bCalcPortion = sal_True; - - while ( nIndex < pNode->GetText().Len() ) - { - sal_Bool bEOL = sal_False; - sal_uInt16 nPortionStart = 0; - sal_uInt16 nPortionEnd = 0; - - sal_uInt16 nTmpPos = nIndex; - sal_uInt16 nTmpPortion = pLine->GetStartPortion(); - long nTmpWidth = mpDoc->GetLeftMargin(); -// long nXWidth = mnMaxTextWidth ? ( mnMaxTextWidth - mpDoc->GetLeftMargin() ) : 0x7FFFFFFF; - // Margin nicht abziehen, ist schon in TmpWidth enthalten. - long nXWidth = mnMaxTextWidth ? mnMaxTextWidth : 0x7FFFFFFF; - if ( nXWidth < nTmpWidth ) - nXWidth = nTmpWidth; - - // Portion suchen, die nicht mehr in Zeile passt.... - TETextPortion* pPortion = 0; - sal_Bool bBrokenLine = sal_False; - bLineBreak = sal_False; - - while ( ( nTmpWidth <= nXWidth ) && !bEOL && ( nTmpPortion < pTEParaPortion->GetTextPortions().size() ) ) - { - nPortionStart = nTmpPos; - pPortion = pTEParaPortion->GetTextPortions()[ nTmpPortion ]; - DBG_ASSERT( pPortion->GetLen(), "Leere Portion in CreateLines ?!" ); - if ( pNode->GetText().GetChar( nTmpPos ) == '\t' ) - { - long nCurPos = nTmpWidth-mpDoc->GetLeftMargin(); - nTmpWidth = ((nCurPos/mnDefTab)+1)*mnDefTab+mpDoc->GetLeftMargin(); - pPortion->GetWidth() = nTmpWidth - nCurPos - mpDoc->GetLeftMargin(); - // Wenn dies das erste Token in der Zeile ist, und - // nTmpWidth > aPaperSize.Width, habe ich eine Endlos-Schleife! - if ( ( nTmpWidth >= nXWidth ) && ( nTmpPortion == pLine->GetStartPortion() ) ) - { - // Aber was jetzt ? Tab passend machen! - pPortion->GetWidth() = nXWidth-1; - nTmpWidth = pPortion->GetWidth(); - bEOL = sal_True; - bBrokenLine = sal_True; - } - pPortion->GetKind() = PORTIONKIND_TAB; - } - else - { - - if ( bCalcPortion || !pPortion->HasValidSize() ) - pPortion->GetWidth() = (long)CalcTextWidth( nPara, nTmpPos, pPortion->GetLen() ); - nTmpWidth += pPortion->GetWidth(); - - pPortion->GetRightToLeft() = ImpGetRightToLeft( nPara, nTmpPos+1 ); - pPortion->GetKind() = PORTIONKIND_TEXT; - } - - nTmpPos = nTmpPos + pPortion->GetLen(); - nPortionEnd = nTmpPos; - nTmpPortion++; - } - - // das war evtl. eine Portion zu weit: - sal_Bool bFixedEnd = sal_False; - if ( nTmpWidth > nXWidth ) - { - nPortionEnd = nTmpPos; - nTmpPos = nTmpPos - pPortion->GetLen(); - nPortionStart = nTmpPos; - nTmpPortion--; - bEOL = sal_False; - - nTmpWidth -= pPortion->GetWidth(); - if ( pPortion->GetKind() == PORTIONKIND_TAB ) - { - bEOL = sal_True; - bFixedEnd = sal_True; - } - } - else - { - bEOL = sal_True; - pLine->SetEnd( nPortionEnd ); - OSL_ENSURE(pTEParaPortion->GetTextPortions().size(), - "No TextPortions?"); - pLine->SetEndPortion( (sal_uInt16)pTEParaPortion->GetTextPortions().size() - 1 ); - } - - if ( bFixedEnd ) - { - pLine->SetEnd( nPortionStart ); - pLine->SetEndPortion( nTmpPortion-1 ); - } - else if ( bLineBreak || bBrokenLine ) - { - pLine->SetEnd( nPortionStart+1 ); - pLine->SetEndPortion( nTmpPortion-1 ); - } - else if ( !bEOL ) - { - DBG_ASSERT( (nPortionEnd-nPortionStart) == pPortion->GetLen(), "Doch eine andere Portion?!" ); - long nRemainingWidth = mnMaxTextWidth - nTmpWidth; - ImpBreakLine( nPara, pLine, pPortion, nPortionStart, nRemainingWidth ); - } - - if ( ( ImpGetAlign() == TXTALIGN_CENTER ) || ( ImpGetAlign() == TXTALIGN_RIGHT ) ) - { - // Ausrichten... - long nTextWidth = 0; - for ( sal_uInt16 nTP = pLine->GetStartPortion(); nTP <= pLine->GetEndPortion(); nTP++ ) - { - TETextPortion* pTextPortion = pTEParaPortion->GetTextPortions()[ nTP ]; - nTextWidth += pTextPortion->GetWidth(); - } - long nSpace = mnMaxTextWidth - nTextWidth; - if ( nSpace > 0 ) - { - if ( ImpGetAlign() == TXTALIGN_CENTER ) - pLine->SetStartX( (sal_uInt16)(nSpace / 2) ); - else // TXTALIGN_RIGHT - pLine->SetStartX( (sal_uInt16)nSpace ); - } - } - else - { - pLine->SetStartX( mpDoc->GetLeftMargin() ); - } - - // ----------------------------------------------------------------- - // pruefen, ob die Zeile neu ausgegeben werden muss... - // ----------------------------------------------------------------- - pLine->SetInvalid(); - - if ( pTEParaPortion->IsSimpleInvalid() ) - { - // Aenderung durch einfache Textaenderung... - // Formatierung nicht abbrechen, da Portions evtl. wieder - // gesplittet werden muessen! - // Wenn irgendwann mal abbrechbar, dann fogende Zeilen Validieren! - // Aber ggf. als Valid markieren, damit weniger Ausgabe... - if ( pLine->GetEnd() < nInvalidStart ) - { - if ( *pLine == aSaveLine ) - { - pLine->SetValid(); - } - } - else - { - sal_uInt16 nStart = pLine->GetStart(); - sal_uInt16 nEnd = pLine->GetEnd(); - - if ( nStart > nInvalidEnd ) - { - if ( ( ( nStart-nInvalidDiff ) == aSaveLine.GetStart() ) && - ( ( nEnd-nInvalidDiff ) == aSaveLine.GetEnd() ) ) - { - pLine->SetValid(); - if ( bCalcPortion && bQuickFormat ) - { - bCalcPortion = sal_False; - pTEParaPortion->CorrectValuesBehindLastFormattedLine( nLine ); - break; - } - } - } - else if ( bQuickFormat && ( nEnd > nInvalidEnd) ) - { - // Wenn die ungueltige Zeile so endet, dass die naechste an - // der 'gleichen' Textstelle wie vorher beginnt, also nicht - // anders umgebrochen wird, brauche ich dort auch nicht die - // textbreiten neu bestimmen: - if ( nEnd == ( aSaveLine.GetEnd() + nInvalidDiff ) ) - { - bCalcPortion = sal_False; - pTEParaPortion->CorrectValuesBehindLastFormattedLine( nLine ); - break; - } - } - } - } - - nIndex = pLine->GetEnd(); // naechste Zeile Start = letzte Zeile Ende - // weil nEnd hinter das letzte Zeichen zeigt! - - sal_uInt16 nEndPortion = pLine->GetEndPortion(); - - // Naechste Zeile oder ggf. neue Zeile.... - pLine = 0; - if ( nLine < pTEParaPortion->GetLines().size()-1 ) - pLine = pTEParaPortion->GetLines()[ ++nLine ]; - if ( pLine && ( nIndex >= pNode->GetText().Len() ) ) - { - nDelFromLine = nLine; - break; - } - if ( !pLine && ( nIndex < pNode->GetText().Len() ) ) - { - pLine = new TextLine; - pTEParaPortion->GetLines().insert( pTEParaPortion->GetLines().begin() + ++nLine, pLine ); - } - if ( pLine ) - { - aSaveLine = *pLine; - pLine->SetStart( nIndex ); - pLine->SetEnd( nIndex ); - pLine->SetStartPortion( nEndPortion+1 ); - pLine->SetEndPortion( nEndPortion+1 ); - } - } // while ( Index < Len ) - - if (nDelFromLine != std::numeric_limits::max()) - { - for( TextLines::iterator it = pTEParaPortion->GetLines().begin() + nDelFromLine; - it != pTEParaPortion->GetLines().end(); ++it ) - { - delete *it; - } - pTEParaPortion->GetLines().erase( pTEParaPortion->GetLines().begin() + nDelFromLine, - pTEParaPortion->GetLines().end() ); - } - - DBG_ASSERT( pTEParaPortion->GetLines().size(), "Keine Zeile nach CreateLines!" ); - - if ( bLineBreak == sal_True ) - CreateAndInsertEmptyLine( nPara ); - - pTEParaPortion->SetValid(); - - return nOldLineCount != pTEParaPortion->GetLines().size(); -} - -String TextEngine::GetWord( const TextPaM& rCursorPos, TextPaM* pStartOfWord ) -{ - String aWord; - if ( rCursorPos.GetPara() < mpDoc->GetNodes().Count() ) - { - TextSelection aSel( rCursorPos ); - TextNode* pNode = mpDoc->GetNodes().GetObject( rCursorPos.GetPara() ); - uno::Reference < i18n::XBreakIterator > xBI = GetBreakIterator(); - i18n::Boundary aBoundary = xBI->getWordBoundary( pNode->GetText(), rCursorPos.GetIndex(), GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True ); - aSel.GetStart().GetIndex() = (sal_uInt16)aBoundary.startPos; - aSel.GetEnd().GetIndex() = (sal_uInt16)aBoundary.endPos; - aWord = pNode->GetText().Copy( aSel.GetStart().GetIndex(), aSel.GetEnd().GetIndex() - aSel.GetStart().GetIndex() ); - if ( pStartOfWord ) - *pStartOfWord = aSel.GetStart(); - } - return aWord; -} - -sal_Bool TextEngine::Read( SvStream& rInput, const TextSelection* pSel ) -{ - sal_Bool bUpdate = GetUpdateMode(); - SetUpdateMode( sal_False ); - - UndoActionStart(); - TextSelection aSel; - if ( pSel ) - aSel = *pSel; - else - { - sal_uLong nParas = mpDoc->GetNodes().Count(); - TextNode* pNode = mpDoc->GetNodes().GetObject( nParas - 1 ); - aSel = TextPaM( nParas-1 , pNode->GetText().Len() ); - } - - if ( aSel.HasRange() ) - aSel = ImpDeleteText( aSel ); - - rtl::OString aLine; - sal_Bool bDone = rInput.ReadLine( aLine ); - rtl::OUString aTmpStr(rtl::OStringToOUString(aLine, rInput.GetStreamCharSet())), aStr; - while ( bDone ) - { - aSel = ImpInsertText( aSel, aTmpStr ); - bDone = rInput.ReadLine( aLine ); - aTmpStr = rtl::OStringToOUString(aLine, rInput.GetStreamCharSet()); - if ( bDone ) - aSel = ImpInsertParaBreak( aSel.GetEnd() ); - } - - UndoActionEnd(); - - TextSelection aNewSel( aSel.GetEnd(), aSel.GetEnd() ); - - // Damit bei FormatAndUpdate nicht auf die ungueltige Selektion zugegriffen wird. - if ( GetActiveView() ) - GetActiveView()->ImpSetSelection( aNewSel ); - - SetUpdateMode( bUpdate ); - FormatAndUpdate( GetActiveView() ); - - return rInput.GetError() ? sal_False : sal_True; -} - -sal_Bool TextEngine::Write( SvStream& rOutput, const TextSelection* pSel, sal_Bool bHTML ) -{ - TextSelection aSel; - if ( pSel ) - aSel = *pSel; - else - { - sal_uLong nParas = mpDoc->GetNodes().Count(); - TextNode* pNode = mpDoc->GetNodes().GetObject( nParas - 1 ); - aSel.GetStart() = TextPaM( 0, 0 ); - aSel.GetEnd() = TextPaM( nParas-1, pNode->GetText().Len() ); - } - - if ( bHTML ) - { - rOutput.WriteLine( "" ); - rOutput.WriteLine( "" ); - } - - for ( sal_uLong nPara = aSel.GetStart().GetPara(); nPara <= aSel.GetEnd().GetPara(); nPara++ ) - { - TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); - - sal_uInt16 nStartPos = 0; - sal_uInt16 nEndPos = pNode->GetText().Len(); - if ( nPara == aSel.GetStart().GetPara() ) - nStartPos = aSel.GetStart().GetIndex(); - if ( nPara == aSel.GetEnd().GetPara() ) - nEndPos = aSel.GetEnd().GetIndex(); - - String aText; - if ( !bHTML ) - { - aText = pNode->GetText().Copy( nStartPos, nEndPos-nStartPos ); - } - else - { - aText.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "

" ) ); - - if ( nStartPos == nEndPos ) - { - // Leerzeilen werden von Writer wegoptimiert - aText.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "
" ) ); - } - else - { - sal_uInt16 nTmpStart = nStartPos; - sal_uInt16 nTmpEnd = nEndPos; - do - { - TextCharAttrib* pAttr = pNode->GetCharAttribs().FindNextAttrib( TEXTATTR_HYPERLINK, nTmpStart, nEndPos ); - nTmpEnd = pAttr ? pAttr->GetStart() : nEndPos; - - // Text vor dem Attribut - aText += pNode->GetText().Copy( nTmpStart, nTmpEnd-nTmpStart ); - - if ( pAttr ) - { - nTmpEnd = Min( pAttr->GetEnd(), nEndPos ); - - // z.B. Morgenpost - aText.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "GetAttr() ).GetURL(); - aText.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "\">" ) ); - nTmpStart = pAttr->GetStart(); - aText += pNode->GetText().Copy( nTmpStart, nTmpEnd-nTmpStart ); - aText.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "" ) ); - - nTmpStart = pAttr->GetEnd(); - } - } while ( nTmpEnd < nEndPos ); - } - - aText.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "

" ) ); - } - rOutput.WriteLine(rtl::OUStringToOString(aText, - rOutput.GetStreamCharSet())); - } - - if ( bHTML ) - { - rOutput.WriteLine( "" ); - rOutput.WriteLine( "" ); - } - - return rOutput.GetError() ? sal_False : sal_True; -} - -void TextEngine::RemoveAttribs( sal_uLong nPara, sal_Bool bIdleFormatAndUpdate ) -{ - if ( nPara < mpDoc->GetNodes().Count() ) - { - TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); - if ( pNode->GetCharAttribs().Count() ) - { - pNode->GetCharAttribs().Clear( sal_True ); - - TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); - pTEParaPortion->MarkSelectionInvalid( 0, pNode->GetText().Len() ); - - mbFormatted = sal_False; - - if ( bIdleFormatAndUpdate ) - IdleFormatAndUpdate( NULL, 0xFFFF ); - else - FormatAndUpdate( NULL ); - } - } -} -void TextEngine::RemoveAttribs( sal_uLong nPara, sal_uInt16 nWhich, sal_Bool bIdleFormatAndUpdate ) -{ - if ( nPara < mpDoc->GetNodes().Count() ) - { - TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); - if ( pNode->GetCharAttribs().Count() ) - { - TextCharAttribList& rAttribs = pNode->GetCharAttribs(); - sal_uInt16 nAttrCount = rAttribs.Count(); - for(sal_uInt16 nAttr = nAttrCount; nAttr; --nAttr) - { - if(rAttribs.GetAttrib( nAttr - 1 )->Which() == nWhich) - rAttribs.RemoveAttrib( nAttr -1 ); - } - TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); - pTEParaPortion->MarkSelectionInvalid( 0, pNode->GetText().Len() ); - mbFormatted = sal_False; - if(bIdleFormatAndUpdate) - IdleFormatAndUpdate( NULL, 0xFFFF ); - else - FormatAndUpdate( NULL ); - } - } -} -void TextEngine::RemoveAttrib( sal_uLong nPara, const TextCharAttrib& rAttrib ) -{ - if ( nPara < mpDoc->GetNodes().Count() ) - { - TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); - if ( pNode->GetCharAttribs().Count() ) - { - TextCharAttribList& rAttribs = pNode->GetCharAttribs(); - sal_uInt16 nAttrCount = rAttribs.Count(); - for(sal_uInt16 nAttr = nAttrCount; nAttr; --nAttr) - { - if(rAttribs.GetAttrib( nAttr - 1 ) == &rAttrib) - { - rAttribs.RemoveAttrib( nAttr -1 ); - break; - } - } - TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); - pTEParaPortion->MarkSelectionInvalid( 0, pNode->GetText().Len() ); - mbFormatted = sal_False; - FormatAndUpdate( NULL ); - } - } -} - -void TextEngine::SetAttrib( const TextAttrib& rAttr, sal_uLong nPara, sal_uInt16 nStart, sal_uInt16 nEnd, sal_Bool bIdleFormatAndUpdate ) -{ - // Es wird hier erstmal nicht geprueft, ob sich Attribute ueberlappen! - // Diese Methode ist erstmal nur fuer einen Editor, der fuer eine Zeile - // _schnell_ das Syntax-Highlight einstellen will. - - // Da die TextEngine z.Zt fuer Editoren gedacht ist gibt es auch kein - // Undo fuer Attribute! - - if ( nPara < mpDoc->GetNodes().Count() ) - { - TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); - TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); - - sal_uInt16 nMax = pNode->GetText().Len(); - if ( nStart > nMax ) - nStart = nMax; - if ( nEnd > nMax ) - nEnd = nMax; - - pNode->GetCharAttribs().InsertAttrib( new TextCharAttrib( rAttr, nStart, nEnd ) ); - pTEParaPortion->MarkSelectionInvalid( nStart, nEnd ); - - mbFormatted = sal_False; - if ( bIdleFormatAndUpdate ) - IdleFormatAndUpdate( NULL, 0xFFFF ); - else - FormatAndUpdate( NULL ); - } -} - -void TextEngine::SetTextAlign( TxtAlign eAlign ) -{ - if ( eAlign != meAlign ) - { - meAlign = eAlign; - FormatFullDoc(); - UpdateViews(); - } -} - - -void TextEngine::ValidateSelection( TextSelection& rSel ) const -{ - ValidatePaM( rSel.GetStart() ); - ValidatePaM( rSel.GetEnd() ); -} - -void TextEngine::ValidatePaM( TextPaM& rPaM ) const -{ - sal_uLong nMaxPara = mpDoc->GetNodes().Count() - 1; - if ( rPaM.GetPara() > nMaxPara ) - { - rPaM.GetPara() = nMaxPara; - rPaM.GetIndex() = 0xFFFF; - } - - sal_uInt16 nMaxIndex = GetTextLen( rPaM.GetPara() ); - if ( rPaM.GetIndex() > nMaxIndex ) - rPaM.GetIndex() = nMaxIndex; -} - - -// Status & Selektionsanpassung - -void TextEngine::ImpParagraphInserted( sal_uLong nPara ) -{ - // Die aktive View braucht nicht angepasst werden, aber bei allen - // passiven muss die Selektion angepasst werden: - if ( mpViews->size() > 1 ) - { - for ( sal_uInt16 nView = mpViews->size(); nView; ) - { - TextView* pView = (*mpViews)[ --nView ]; - if ( pView != GetActiveView() ) - { - for ( int n = 0; n <= 1; n++ ) - { - TextPaM& rPaM = n ? pView->GetSelection().GetStart(): pView->GetSelection().GetEnd(); - if ( rPaM.GetPara() >= nPara ) - rPaM.GetPara()++; - } - } - } - } - Broadcast( TextHint( TEXT_HINT_PARAINSERTED, nPara ) ); -} - -void TextEngine::ImpParagraphRemoved( sal_uLong nPara ) -{ - if ( mpViews->size() > 1 ) - { - for ( sal_uInt16 nView = mpViews->size(); nView; ) - { - TextView* pView = (*mpViews)[ --nView ]; - if ( pView != GetActiveView() ) - { - sal_uLong nParas = mpDoc->GetNodes().Count(); - for ( int n = 0; n <= 1; n++ ) - { - TextPaM& rPaM = n ? pView->GetSelection().GetStart(): pView->GetSelection().GetEnd(); - if ( rPaM.GetPara() > nPara ) - rPaM.GetPara()--; - else if ( rPaM.GetPara() == nPara ) - { - rPaM.GetIndex() = 0; - if ( rPaM.GetPara() >= nParas ) - rPaM.GetPara()--; - } - } - } - } - } - Broadcast( TextHint( TEXT_HINT_PARAREMOVED, nPara ) ); -} - -void TextEngine::ImpCharsRemoved( sal_uLong nPara, sal_uInt16 nPos, sal_uInt16 nChars ) -{ - if ( mpViews->size() > 1 ) - { - for ( sal_uInt16 nView = mpViews->size(); nView; ) - { - TextView* pView = (*mpViews)[ --nView ]; - if ( pView != GetActiveView() ) - { - sal_uInt16 nEnd = nPos+nChars; - for ( int n = 0; n <= 1; n++ ) - { - TextPaM& rPaM = n ? pView->GetSelection().GetStart(): pView->GetSelection().GetEnd(); - if ( rPaM.GetPara() == nPara ) - { - if ( rPaM.GetIndex() > nEnd ) - rPaM.GetIndex() = rPaM.GetIndex() - nChars; - else if ( rPaM.GetIndex() > nPos ) - rPaM.GetIndex() = nPos; - } - } - } - } - } - Broadcast( TextHint( TEXT_HINT_PARACONTENTCHANGED, nPara ) ); -} - -void TextEngine::ImpCharsInserted( sal_uLong nPara, sal_uInt16 nPos, sal_uInt16 nChars ) -{ - if ( mpViews->size() > 1 ) - { - for ( sal_uInt16 nView = mpViews->size(); nView; ) - { - TextView* pView = (*mpViews)[ --nView ]; - if ( pView != GetActiveView() ) - { - for ( int n = 0; n <= 1; n++ ) - { - TextPaM& rPaM = n ? pView->GetSelection().GetStart(): pView->GetSelection().GetEnd(); - if ( rPaM.GetPara() == nPara ) - { - if ( rPaM.GetIndex() >= nPos ) - rPaM.GetIndex() = rPaM.GetIndex() + nChars; - } - } - } - } - } - Broadcast( TextHint( TEXT_HINT_PARACONTENTCHANGED, nPara ) ); -} - -void TextEngine::ImpFormattingParagraph( sal_uLong nPara ) -{ - Broadcast( TextHint( TEXT_HINT_FORMATPARA, nPara ) ); -} - -void TextEngine::ImpTextHeightChanged() -{ - Broadcast( TextHint( TEXT_HINT_TEXTHEIGHTCHANGED ) ); -} - -void TextEngine::ImpTextFormatted() -{ - Broadcast( TextHint( TEXT_HINT_TEXTFORMATTED ) ); -} - -void TextEngine::Draw( OutputDevice* pDev, const Point& rPos ) -{ - ImpPaint( pDev, rPos, NULL ); -} - -void TextEngine::SetLeftMargin( sal_uInt16 n ) -{ - mpDoc->SetLeftMargin( n ); -} - -sal_uInt16 TextEngine::GetLeftMargin() const -{ - return mpDoc->GetLeftMargin(); -} - -uno::Reference< i18n::XBreakIterator > TextEngine::GetBreakIterator() -{ - if ( !mxBreakIterator.is() ) - mxBreakIterator = vcl::unohelper::CreateBreakIterator(); - DBG_ASSERT( mxBreakIterator.is(), "Could not create BreakIterator" ); - return mxBreakIterator; -} - -void TextEngine::SetLocale( const ::com::sun::star::lang::Locale& rLocale ) -{ - maLocale = rLocale; - delete mpLocaleDataWrapper; - mpLocaleDataWrapper = NULL; -} - -::com::sun::star::lang::Locale TextEngine::GetLocale() -{ - if ( maLocale.Language.isEmpty() ) - { - maLocale = Application::GetSettings().GetUILocale(); - } - return maLocale; -} - -LocaleDataWrapper* TextEngine::ImpGetLocaleDataWrapper() -{ - if ( !mpLocaleDataWrapper ) - mpLocaleDataWrapper = new LocaleDataWrapper( vcl::unohelper::GetMultiServiceFactory(), GetLocale() ); - - return mpLocaleDataWrapper; -} - -void TextEngine::SetRightToLeft( sal_Bool bR2L ) -{ - if ( mbRightToLeft != bR2L ) - { - mbRightToLeft = bR2L; - meAlign = bR2L ? TXTALIGN_RIGHT : TXTALIGN_LEFT; - FormatFullDoc(); - UpdateViews(); - } -} - -void TextEngine::ImpInitWritingDirections( sal_uLong nPara ) -{ - TEParaPortion* pParaPortion = mpTEParaPortions->GetObject( nPara ); - std::vector& rInfos = pParaPortion->GetWritingDirectionInfos(); - rInfos.clear(); - - if ( pParaPortion->GetNode()->GetText().Len() ) - { - const UBiDiLevel nBidiLevel = IsRightToLeft() ? 1 /*RTL*/ : 0 /*LTR*/; - String aText( pParaPortion->GetNode()->GetText() ); - - // - // Bidi functions from icu 2.0 - // - UErrorCode nError = U_ZERO_ERROR; - UBiDi* pBidi = ubidi_openSized( aText.Len(), 0, &nError ); - nError = U_ZERO_ERROR; - - ubidi_setPara( pBidi, reinterpret_cast(aText.GetBuffer()), aText.Len(), nBidiLevel, NULL, &nError ); // UChar != sal_Unicode in MinGW - nError = U_ZERO_ERROR; - - long nCount = ubidi_countRuns( pBidi, &nError ); - - int32_t nStart = 0; - int32_t nEnd; - UBiDiLevel nCurrDir; - - for ( sal_uInt16 nIdx = 0; nIdx < nCount; ++nIdx ) - { - ubidi_getLogicalRun( pBidi, nStart, &nEnd, &nCurrDir ); - rInfos.push_back( TEWritingDirectionInfo( nCurrDir, (sal_uInt16)nStart, (sal_uInt16)nEnd ) ); - nStart = nEnd; - } - - ubidi_close( pBidi ); - } - - // No infos mean no CTL and default dir is L2R... - if ( rInfos.empty() ) - rInfos.push_back( TEWritingDirectionInfo( 0, 0, (sal_uInt16)pParaPortion->GetNode()->GetText().Len() ) ); - -} - -sal_uInt8 TextEngine::ImpGetRightToLeft( sal_uLong nPara, sal_uInt16 nPos, sal_uInt16* pStart, sal_uInt16* pEnd ) -{ - sal_uInt8 nRightToLeft = 0; - - TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); - if ( pNode && pNode->GetText().Len() ) - { - TEParaPortion* pParaPortion = mpTEParaPortions->GetObject( nPara ); - if ( pParaPortion->GetWritingDirectionInfos().empty() ) - ImpInitWritingDirections( nPara ); - - std::vector& rDirInfos = pParaPortion->GetWritingDirectionInfos(); - for ( std::vector::const_iterator rDirInfosIt = rDirInfos.begin(); rDirInfosIt != rDirInfos.end(); ++rDirInfosIt ) - { - if ( ( (*rDirInfosIt).nStartPos <= nPos ) && ( (*rDirInfosIt).nEndPos >= nPos ) ) - { - nRightToLeft = (*rDirInfosIt).nType; - if ( pStart ) - *pStart = (*rDirInfosIt).nStartPos; - if ( pEnd ) - *pEnd = (*rDirInfosIt).nEndPos; - break; - } - } - } - return nRightToLeft; -} - -long TextEngine::ImpGetPortionXOffset( sal_uLong nPara, TextLine* pLine, sal_uInt16 nTextPortion ) -{ - long nX = pLine->GetStartX(); - - TEParaPortion* pParaPortion = mpTEParaPortions->GetObject( nPara ); - - for ( sal_uInt16 i = pLine->GetStartPortion(); i < nTextPortion; i++ ) - { - TETextPortion* pPortion = pParaPortion->GetTextPortions()[ i ]; - nX += pPortion->GetWidth(); - } - - TETextPortion* pDestPortion = pParaPortion->GetTextPortions()[ nTextPortion ]; - if ( pDestPortion->GetKind() != PORTIONKIND_TAB ) - { - if ( !IsRightToLeft() && pDestPortion->GetRightToLeft() ) - { - // Portions behind must be added, visual before this portion - sal_uInt16 nTmpPortion = nTextPortion+1; - while ( nTmpPortion <= pLine->GetEndPortion() ) - { - TETextPortion* pNextTextPortion = pParaPortion->GetTextPortions()[ nTmpPortion ]; - if ( pNextTextPortion->GetRightToLeft() && ( pNextTextPortion->GetKind() != PORTIONKIND_TAB ) ) - nX += pNextTextPortion->GetWidth(); - else - break; - nTmpPortion++; - } - // Portions before must be removed, visual behind this portion - nTmpPortion = nTextPortion; - while ( nTmpPortion > pLine->GetStartPortion() ) - { - --nTmpPortion; - TETextPortion* pPrevTextPortion = pParaPortion->GetTextPortions()[ nTmpPortion ]; - if ( pPrevTextPortion->GetRightToLeft() && ( pPrevTextPortion->GetKind() != PORTIONKIND_TAB ) ) - nX -= pPrevTextPortion->GetWidth(); - else - break; - } - } - else if ( IsRightToLeft() && !pDestPortion->IsRightToLeft() ) - { - // Portions behind must be removed, visual behind this portion - sal_uInt16 nTmpPortion = nTextPortion+1; - while ( nTmpPortion <= pLine->GetEndPortion() ) - { - TETextPortion* pNextTextPortion = pParaPortion->GetTextPortions()[ nTmpPortion ]; - if ( !pNextTextPortion->IsRightToLeft() && ( pNextTextPortion->GetKind() != PORTIONKIND_TAB ) ) - nX += pNextTextPortion->GetWidth(); - else - break; - nTmpPortion++; - } - // Portions before must be added, visual before this portion - nTmpPortion = nTextPortion; - while ( nTmpPortion > pLine->GetStartPortion() ) - { - --nTmpPortion; - TETextPortion* pPrevTextPortion = pParaPortion->GetTextPortions()[ nTmpPortion ]; - if ( !pPrevTextPortion->IsRightToLeft() && ( pPrevTextPortion->GetKind() != PORTIONKIND_TAB ) ) - nX -= pPrevTextPortion->GetWidth(); - else - break; - } - } - } - - return nX; -} - -void TextEngine::ImpInitLayoutMode( OutputDevice* pOutDev, sal_Bool bDrawingR2LPortion ) -{ - sal_uLong nLayoutMode = pOutDev->GetLayoutMode(); - - nLayoutMode &= ~(TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_COMPLEX_DISABLED | TEXT_LAYOUT_BIDI_STRONG ); - if ( bDrawingR2LPortion ) - nLayoutMode |= TEXT_LAYOUT_BIDI_RTL; - - pOutDev->SetLayoutMode( nLayoutMode ); -} - -TxtAlign TextEngine::ImpGetAlign() const -{ - TxtAlign eAlign = meAlign; - if ( IsRightToLeft() ) - { - if ( eAlign == TXTALIGN_LEFT ) - eAlign = TXTALIGN_RIGHT; - else if ( eAlign == TXTALIGN_RIGHT ) - eAlign = TXTALIGN_LEFT; - } - return eAlign; -} - -long TextEngine::ImpGetOutputOffset( sal_uLong nPara, TextLine* pLine, sal_uInt16 nIndex, sal_uInt16 nIndex2 ) -{ - TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPara ); - - sal_uInt16 nPortionStart; - sal_uInt16 nPortion = pPortion->GetTextPortions().FindPortion( nIndex, nPortionStart, sal_True ); - - TETextPortion* pTextPortion = pPortion->GetTextPortions()[ nPortion ]; - - long nX; - - if ( ( nIndex == nPortionStart ) && ( nIndex == nIndex2 ) ) - { - // Output of full portion, so we need portion x offset. - // Use ImpGetPortionXOffset, because GetXPos may deliver left or right position from portioon, depending on R2L, L2R - nX = ImpGetPortionXOffset( nPara, pLine, nPortion ); - if ( IsRightToLeft() ) - { - nX = -nX -pTextPortion->GetWidth(); - } - } - else - { - nX = ImpGetXPos( nPara, pLine, nIndex, nIndex == nPortionStart ); - if ( nIndex2 != nIndex ) - { - long nX2 = ImpGetXPos( nPara, pLine, nIndex2, sal_False ); - if ( ( !IsRightToLeft() && ( nX2 < nX ) ) || - ( IsRightToLeft() && ( nX2 > nX ) ) ) - { - nX = nX2; - } - } - if ( IsRightToLeft() ) - { - nX = -nX; - } - } - - return nX; -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svtools/source/edit/textund2.hxx b/svtools/source/edit/textund2.hxx deleted file mode 100644 index c5ce90c..0000000 --- a/svtools/source/edit/textund2.hxx +++ /dev/null @@ -1,122 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ -#ifndef _TEXTUND2_HXX -#define _TEXTUND2_HXX - -#include - - -class TextUndoDelPara : public TextUndo -{ -private: - sal_Bool mbDelObject; - sal_uLong mnPara; - TextNode* mpNode; // Zeigt auf das gueltige, nicht zerstoerte Objekt! - -public: - TYPEINFO(); - TextUndoDelPara( TextEngine* pTextEngine, TextNode* pNode, sal_uLong nPara ); - ~TextUndoDelPara(); - - virtual void Undo(); - virtual void Redo(); -}; - - -class TextUndoConnectParas : public TextUndo -{ -private: - sal_uLong mnPara; - sal_uInt16 mnSepPos; - -public: - TYPEINFO(); - TextUndoConnectParas( TextEngine* pTextEngine, sal_uLong nPara, sal_uInt16 nSepPos ); - ~TextUndoConnectParas(); - - virtual void Undo(); - virtual void Redo(); -}; - - -class TextUndoSplitPara : public TextUndo -{ -private: - sal_uLong mnPara; - sal_uInt16 mnSepPos; - -public: - TYPEINFO(); - TextUndoSplitPara( TextEngine* pTextEngine, sal_uLong nPara, sal_uInt16 nSepPos ); - ~TextUndoSplitPara(); - - virtual void Undo(); - virtual void Redo(); -}; - - -class TextUndoInsertChars : public TextUndo -{ -private: - TextPaM maTextPaM; - String maText; - -public: - TYPEINFO(); - TextUndoInsertChars( TextEngine* pTextEngine, const TextPaM& rTextPaM, const String& rStr ); - - virtual void Undo(); - virtual void Redo(); - - virtual sal_Bool Merge( SfxUndoAction *pNextAction ); -}; - - -class TextUndoRemoveChars : public TextUndo -{ -private: - TextPaM maTextPaM; - String maText; - -public: - TYPEINFO(); - TextUndoRemoveChars( TextEngine* pTextEngine, const TextPaM& rTextPaM, const String& rStr ); - - virtual void Undo(); - virtual void Redo(); -}; - - -class TextUndoSetAttribs: public TextUndo -{ -private: - TextSelection maSelection; - -public: - TYPEINFO(); - TextUndoSetAttribs( TextEngine* pTextEngine, const TextSelection& rESel ); - ~TextUndoSetAttribs(); - - virtual void Undo(); - virtual void Redo(); -}; - -#endif // _TEXTUND2_HXX - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svtools/source/edit/textundo.cxx b/svtools/source/edit/textundo.cxx deleted file mode 100644 index 1b82d0f..0000000 --- a/svtools/source/edit/textundo.cxx +++ /dev/null @@ -1,295 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2000, 2010 Oracle and/or its affiliates. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * - * for a copy of the LGPLv3 License. - * - ************************************************************************/ - - -#include -#include -#include -#include -#include -#include -#include - -TYPEINIT1( TextUndo, SfxUndoAction ); -TYPEINIT1( TextUndoDelPara, TextUndo ); -TYPEINIT1( TextUndoConnectParas, TextUndo ); -TYPEINIT1( TextUndoSplitPara, TextUndo ); -TYPEINIT1( TextUndoInsertChars, TextUndo ); -TYPEINIT1( TextUndoRemoveChars, TextUndo ); - - -TextUndoManager::TextUndoManager( TextEngine* p ) -{ - mpTextEngine = p; -} - -TextUndoManager::~TextUndoManager() -{ -} - -sal_Bool TextUndoManager::Undo() -{ - if ( GetUndoActionCount() == 0 ) - return sal_False; - - UndoRedoStart(); - - mpTextEngine->SetIsInUndo( sal_True ); - sal_Bool bDone = SfxUndoManager::Undo(); - mpTextEngine->SetIsInUndo( sal_False ); - - UndoRedoEnd(); - - return bDone; -} - -sal_Bool TextUndoManager::Redo() -{ - if ( GetRedoActionCount() == 0 ) - return sal_False; - - - UndoRedoStart(); - - mpTextEngine->SetIsInUndo( sal_True ); - sal_Bool bDone = SfxUndoManager::Redo(); - mpTextEngine->SetIsInUndo( sal_False ); - - UndoRedoEnd(); - - return bDone; -} - -void TextUndoManager::UndoRedoStart() -{ - DBG_ASSERT( GetView(), "Undo/Redo: Active View?" ); - -// if ( GetView() ) -// GetView()->HideSelection(); -} - -void TextUndoManager::UndoRedoEnd() -{ - if ( GetView() ) - { - TextSelection aNewSel( GetView()->GetSelection() ); - aNewSel.GetStart() = aNewSel.GetEnd(); - GetView()->ImpSetSelection( aNewSel ); - } - - mpTextEngine->UpdateSelections(); - - mpTextEngine->FormatAndUpdate( GetView() ); -} - - -TextUndo::TextUndo( TextEngine* p ) -{ - mpTextEngine = p; -} - -TextUndo::~TextUndo() -{ -} - -rtl::OUString TextUndo::GetComment() const -{ - return rtl::OUString(); -} - -void TextUndo::SetSelection( const TextSelection& rSel ) -{ - if ( GetView() ) - GetView()->ImpSetSelection( rSel ); -} - - -TextUndoDelPara::TextUndoDelPara( TextEngine* pTextEngine, TextNode* pNode, sal_uLong nPara ) - : TextUndo( pTextEngine ) -{ - mpNode = pNode; - mnPara = nPara; - mbDelObject = sal_True; -} - -TextUndoDelPara::~TextUndoDelPara() -{ - if ( mbDelObject ) - delete mpNode; -} - -void TextUndoDelPara::Undo() -{ - GetTextEngine()->InsertContent( mpNode, mnPara ); - mbDelObject = sal_False; // gehoert wieder der Engine - - if ( GetView() ) - { - TextSelection aSel( TextPaM( mnPara, 0 ), TextPaM( mnPara, mpNode->GetText().Len() ) ); - SetSelection( aSel ); - } -} - -void TextUndoDelPara::Redo() -{ - // pNode stimmt nicht mehr, falls zwischendurch Undos, in denen - // Absaetze verschmolzen sind. - mpNode = GetDoc()->GetNodes().GetObject( mnPara ); - - delete GetTEParaPortions()->GetObject( mnPara ); - GetTEParaPortions()->Remove( mnPara ); - - // Node nicht loeschen, haengt im Undo! - GetDoc()->GetNodes().Remove( mnPara ); - GetTextEngine()->ImpParagraphRemoved( mnPara ); - - mbDelObject = sal_True; // gehoert wieder dem Undo - - sal_uLong nParas = GetDoc()->GetNodes().Count(); - sal_uLong n = mnPara < nParas ? mnPara : (nParas-1); - TextNode* pN = GetDoc()->GetNodes().GetObject( n ); - TextPaM aPaM( n, pN->GetText().Len() ); - SetSelection( aPaM ); -} - -// ----------------------------------------------------------------------- -// TextUndoConnectParas -// ------------------------------------------------------------------------ -TextUndoConnectParas::TextUndoConnectParas( TextEngine* pTextEngine, sal_uLong nPara, sal_uInt16 nPos ) - : TextUndo( pTextEngine ) -{ - mnPara = nPara; - mnSepPos = nPos; -} - -TextUndoConnectParas::~TextUndoConnectParas() -{ -} - -void TextUndoConnectParas::Undo() -{ - TextPaM aPaM = GetTextEngine()->SplitContent( mnPara, mnSepPos ); - SetSelection( aPaM ); -} - -void TextUndoConnectParas::Redo() -{ - TextPaM aPaM = GetTextEngine()->ConnectContents( mnPara ); - SetSelection( aPaM ); -} - - -TextUndoSplitPara::TextUndoSplitPara( TextEngine* pTextEngine, sal_uLong nPara, sal_uInt16 nPos ) - : TextUndo( pTextEngine ) -{ - mnPara = nPara; - mnSepPos = nPos; -} - -TextUndoSplitPara::~TextUndoSplitPara() -{ -} - -void TextUndoSplitPara::Undo() -{ - TextPaM aPaM = GetTextEngine()->ConnectContents( mnPara ); - SetSelection( aPaM ); -} - -void TextUndoSplitPara::Redo() -{ - TextPaM aPaM = GetTextEngine()->SplitContent( mnPara, mnSepPos ); - SetSelection( aPaM ); -} - - -TextUndoInsertChars::TextUndoInsertChars( TextEngine* pTextEngine, const TextPaM& rTextPaM, const XubString& rStr ) - : TextUndo( pTextEngine ), - maTextPaM( rTextPaM ), maText( rStr ) -{ -} - -void TextUndoInsertChars::Undo() -{ - TextSelection aSel( maTextPaM, maTextPaM ); - aSel.GetEnd().GetIndex() = aSel.GetEnd().GetIndex() + maText.Len(); - TextPaM aPaM = GetTextEngine()->ImpDeleteText( aSel ); - SetSelection( aPaM ); -} - -void TextUndoInsertChars::Redo() -{ - TextSelection aSel( maTextPaM, maTextPaM ); - GetTextEngine()->ImpInsertText( aSel, maText ); - TextPaM aNewPaM( maTextPaM ); - aNewPaM.GetIndex() = aNewPaM.GetIndex() + maText.Len(); - SetSelection( TextSelection( aSel.GetStart(), aNewPaM ) ); -} - -sal_Bool TextUndoInsertChars::Merge( SfxUndoAction* pNextAction ) -{ - if ( !pNextAction->ISA( TextUndoInsertChars ) ) - return sal_False; - - TextUndoInsertChars* pNext = (TextUndoInsertChars*)pNextAction; - - if ( maTextPaM.GetPara() != pNext->maTextPaM.GetPara() ) - return sal_False; - - if ( ( maTextPaM.GetIndex() + maText.Len() ) == pNext->maTextPaM.GetIndex() ) - { - maText += pNext->maText; - return sal_True; - } - return sal_False; -} - - -TextUndoRemoveChars::TextUndoRemoveChars( TextEngine* pTextEngine, const TextPaM& rTextPaM, const XubString& rStr ) - : TextUndo( pTextEngine ), - maTextPaM( rTextPaM ), maText( rStr ) -{ -} - -void TextUndoRemoveChars::Undo() -{ - TextSelection aSel( maTextPaM, maTextPaM ); - GetTextEngine()->ImpInsertText( aSel, maText ); - aSel.GetEnd().GetIndex() = aSel.GetEnd().GetIndex() + maText.Len(); - SetSelection( aSel ); -} - -void TextUndoRemoveChars::Redo() -{ - TextSelection aSel( maTextPaM, maTextPaM ); - aSel.GetEnd().GetIndex() = aSel.GetEnd().GetIndex() + maText.Len(); - TextPaM aPaM = GetTextEngine()->ImpDeleteText( aSel ); - SetSelection( aPaM ); -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svtools/source/edit/textundo.hxx b/svtools/source/edit/textundo.hxx deleted file mode 100644 index f86f877..0000000 --- a/svtools/source/edit/textundo.hxx +++ /dev/null @@ -1,85 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2000, 2010 Oracle and/or its affiliates. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * - * for a copy of the LGPLv3 License. - * - ************************************************************************/ -#ifndef _TEXTUNDO_HXX -#define _TEXTUNDO_HXX - -#include - -class TextEngine; - -class TextUndoManager : public SfxUndoManager -{ - TextEngine* mpTextEngine; - -protected: - - void UndoRedoStart(); - void UndoRedoEnd(); - - TextView* GetView() const { return mpTextEngine->GetActiveView(); } - -public: - TextUndoManager( TextEngine* pTextEngine ); - ~TextUndoManager(); - - using SfxUndoManager::Undo; - virtual sal_Bool Undo(); - using SfxUndoManager::Redo; - virtual sal_Bool Redo(); - -}; - -class TextUndo : public SfxUndoAction -{ -private: - TextEngine* mpTextEngine; - -protected: - - TextView* GetView() const { return mpTextEngine->GetActiveView(); } - void SetSelection( const TextSelection& rSel ); - - TextDoc* GetDoc() const { return mpTextEngine->mpDoc; } - TEParaPortions* GetTEParaPortions() const { return mpTextEngine->mpTEParaPortions; } - -public: - TYPEINFO(); - TextUndo( TextEngine* pTextEngine ); - virtual ~TextUndo(); - - TextEngine* GetTextEngine() const { return mpTextEngine; } - - virtual void Undo() = 0; - virtual void Redo() = 0; - - virtual rtl::OUString GetComment() const; -}; - -#endif // _TEXTUNDO_HXX - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svtools/source/edit/textview.cxx b/svtools/source/edit/textview.cxx deleted file mode 100644 index 40a6774..0000000 --- a/svtools/source/edit/textview.cxx +++ /dev/null @@ -1,2378 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2000, 2010 Oracle and/or its affiliates. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * - * for a copy of the LGPLv3 License. - * - ************************************************************************/ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - - -#include - -#include - - -using namespace ::com::sun::star; - -class TETextDataObject : public ::com::sun::star::datatransfer::XTransferable, - public ::cppu::OWeakObject - -{ -private: - String maText; - SvMemoryStream maHTMLStream; - -public: - TETextDataObject( const String& rText ); - ~TETextDataObject(); - - String& GetText() { return maText; } - SvMemoryStream& GetHTMLStream() { return maHTMLStream; } - - // ::com::sun::star::uno::XInterface - ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type & rType ) throw(::com::sun::star::uno::RuntimeException); - void SAL_CALL acquire() throw() { OWeakObject::acquire(); } - void SAL_CALL release() throw() { OWeakObject::release(); } - - // ::com::sun::star::datatransfer::XTransferable - ::com::sun::star::uno::Any SAL_CALL getTransferData( const ::com::sun::star::datatransfer::DataFlavor& aFlavor ) throw(::com::sun::star::datatransfer::UnsupportedFlavorException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); - ::com::sun::star::uno::Sequence< ::com::sun::star::datatransfer::DataFlavor > SAL_CALL getTransferDataFlavors( ) throw(::com::sun::star::uno::RuntimeException); - sal_Bool SAL_CALL isDataFlavorSupported( const ::com::sun::star::datatransfer::DataFlavor& aFlavor ) throw(::com::sun::star::uno::RuntimeException); -}; - -TETextDataObject::TETextDataObject( const String& rText ) : maText( rText ) -{ -} - -TETextDataObject::~TETextDataObject() -{ -} - -// uno::XInterface -uno::Any TETextDataObject::queryInterface( const uno::Type & rType ) throw(uno::RuntimeException) -{ - uno::Any aRet = ::cppu::queryInterface( rType, (static_cast< datatransfer::XTransferable* >(this)) ); - return (aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType )); -} - -// datatransfer::XTransferable -uno::Any TETextDataObject::getTransferData( const datatransfer::DataFlavor& rFlavor ) throw(datatransfer::UnsupportedFlavorException, io::IOException, uno::RuntimeException) -{ - uno::Any aAny; - - sal_uLong nT = SotExchange::GetFormat( rFlavor ); - if ( nT == SOT_FORMAT_STRING ) - { - aAny <<= (::rtl::OUString)GetText(); - } - else if ( nT == SOT_FORMATSTR_ID_HTML ) - { - GetHTMLStream().Seek( STREAM_SEEK_TO_END ); - sal_uLong nLen = GetHTMLStream().Tell(); - GetHTMLStream().Seek(0); - - uno::Sequence< sal_Int8 > aSeq( nLen ); - memcpy( aSeq.getArray(), GetHTMLStream().GetData(), nLen ); - aAny <<= aSeq; - } - else - { - throw datatransfer::UnsupportedFlavorException(); - } - return aAny; -} - -uno::Sequence< datatransfer::DataFlavor > TETextDataObject::getTransferDataFlavors( ) throw(uno::RuntimeException) -{ - GetHTMLStream().Seek( STREAM_SEEK_TO_END ); - sal_Bool bHTML = GetHTMLStream().Tell() > 0; - uno::Sequence< datatransfer::DataFlavor > aDataFlavors( bHTML ? 2 : 1 ); - SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aDataFlavors.getArray()[0] ); - if ( bHTML ) - SotExchange::GetFormatDataFlavor( SOT_FORMATSTR_ID_HTML, aDataFlavors.getArray()[1] ); - return aDataFlavors; -} - -sal_Bool TETextDataObject::isDataFlavorSupported( const datatransfer::DataFlavor& rFlavor ) throw(uno::RuntimeException) -{ - sal_uLong nT = SotExchange::GetFormat( rFlavor ); - return ( nT == SOT_FORMAT_STRING ); -} - -struct ImpTextView -{ - TextEngine* mpTextEngine; - - Window* mpWindow; - TextSelection maSelection; - Point maStartDocPos; -// TextPaM maMBDownPaM; - - Cursor* mpCursor; - - TextDDInfo* mpDDInfo; - - VirtualDevice* mpVirtDev; - - SelectionEngine* mpSelEngine; - TextSelFunctionSet* mpSelFuncSet; - - ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSourceListener > mxDnDListener; - - sal_uInt16 mnTravelXPos; - - sal_Bool mbAutoScroll : 1; - sal_Bool mbInsertMode : 1; - sal_Bool mbReadOnly : 1; - sal_Bool mbPaintSelection : 1; - sal_Bool mbAutoIndent : 1; - sal_Bool mbHighlightSelection : 1; - sal_Bool mbCursorEnabled : 1; - sal_Bool mbClickedInSelection : 1; - sal_Bool mbSupportProtectAttribute : 1; - bool mbCursorAtEndOfLine; -}; - -// ------------------------------------------------------------------------- -// (+) class TextView -// ------------------------------------------------------------------------- -TextView::TextView( TextEngine* pEng, Window* pWindow ) : - mpImpl(new ImpTextView) -{ - pWindow->EnableRTL( sal_False ); - - mpImpl->mpWindow = pWindow; - mpImpl->mpTextEngine = pEng; - mpImpl->mpVirtDev = NULL; - - mpImpl->mbPaintSelection = sal_True; - mpImpl->mbAutoScroll = sal_True; - mpImpl->mbInsertMode = sal_True; - mpImpl->mbReadOnly = sal_False; - mpImpl->mbHighlightSelection = sal_False; - mpImpl->mbAutoIndent = sal_False; - mpImpl->mbCursorEnabled = sal_True; - mpImpl->mbClickedInSelection = sal_False; - mpImpl->mbSupportProtectAttribute = sal_False; - mpImpl->mbCursorAtEndOfLine = false; -// mbInSelection = sal_False; - - mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW; - - mpImpl->mpSelFuncSet = new TextSelFunctionSet( this ); - mpImpl->mpSelEngine = new SelectionEngine( mpImpl->mpWindow, mpImpl->mpSelFuncSet ); - mpImpl->mpSelEngine->SetSelectionMode( RANGE_SELECTION ); - mpImpl->mpSelEngine->EnableDrag( sal_True ); - - mpImpl->mpCursor = new Cursor; - mpImpl->mpCursor->Show(); - pWindow->SetCursor( mpImpl->mpCursor ); - pWindow->SetInputContext( InputContext( pEng->GetFont(), INPUTCONTEXT_TEXT|INPUTCONTEXT_EXTTEXTINPUT ) ); - - if ( pWindow->GetSettings().GetStyleSettings().GetSelectionOptions() & SELECTION_OPTION_INVERT ) - mpImpl->mbHighlightSelection = sal_True; - - pWindow->SetLineColor(); - - mpImpl->mpDDInfo = NULL; - - if ( pWindow->GetDragGestureRecognizer().is() ) - { - vcl::unohelper::DragAndDropWrapper* pDnDWrapper = new vcl::unohelper::DragAndDropWrapper( this ); - mpImpl->mxDnDListener = pDnDWrapper; - - uno::Reference< datatransfer::dnd::XDragGestureListener> xDGL( mpImpl->mxDnDListener, uno::UNO_QUERY ); - pWindow->GetDragGestureRecognizer()->addDragGestureListener( xDGL ); - uno::Reference< datatransfer::dnd::XDropTargetListener> xDTL( xDGL, uno::UNO_QUERY ); - pWindow->GetDropTarget()->addDropTargetListener( xDTL ); - pWindow->GetDropTarget()->setActive( sal_True ); - pWindow->GetDropTarget()->setDefaultActions( datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE ); - } -} - -TextView::~TextView() -{ - delete mpImpl->mpSelEngine; - delete mpImpl->mpSelFuncSet; - delete mpImpl->mpVirtDev; - - if ( mpImpl->mpWindow->GetCursor() == mpImpl->mpCursor ) - mpImpl->mpWindow->SetCursor( 0 ); - delete mpImpl->mpCursor; - delete mpImpl->mpDDInfo; - delete mpImpl; -} - -void TextView::Invalidate() -{ - mpImpl->mpWindow->Invalidate(); -} - -void TextView::SetSelection( const TextSelection& rTextSel, sal_Bool bGotoCursor ) -{ - // Falls jemand gerade ein leeres Attribut hinterlassen hat, - // und dann der Outliner die Selektion manipulitert: - if ( !mpImpl->maSelection.HasRange() ) - mpImpl->mpTextEngine->CursorMoved( mpImpl->maSelection.GetStart().GetPara() ); - - // Wenn nach einem KeyInput die Selection manipuliert wird: - mpImpl->mpTextEngine->CheckIdleFormatter(); - - HideSelection(); - TextSelection aNewSel( rTextSel ); - mpImpl->mpTextEngine->ValidateSelection( aNewSel ); - ImpSetSelection( aNewSel ); - ShowSelection(); - ShowCursor( bGotoCursor ); -} - -void TextView::SetSelection( const TextSelection& rTextSel ) -{ - SetSelection( rTextSel, mpImpl->mbAutoScroll ); -} - -const TextSelection& TextView::GetSelection() const -{ - return mpImpl->maSelection; -} -TextSelection& TextView::GetSelection() -{ - return mpImpl->maSelection; -} - -void TextView::DeleteSelected() -{ -// HideSelection(); - - mpImpl->mpTextEngine->UndoActionStart(); - TextPaM aPaM = mpImpl->mpTextEngine->ImpDeleteText( mpImpl->maSelection ); - mpImpl->mpTextEngine->UndoActionEnd(); - - ImpSetSelection( aPaM ); - mpImpl->mpTextEngine->FormatAndUpdate( this ); - ShowCursor(); -} - -void TextView::ImpPaint( OutputDevice* pOut, const Point& rStartPos, Rectangle const* pPaintArea, TextSelection const* pPaintRange, TextSelection const* pSelection ) -{ - if ( !mpImpl->mbPaintSelection ) - pSelection = NULL; - else - { - // Richtige Hintergrundfarbe einstellen. - // Ich bekomme leider nicht mit, ob sich diese inzwischen geaendert hat. - Font aFont = mpImpl->mpTextEngine->GetFont(); - Color aColor = pOut->GetBackground().GetColor(); - aColor.SetTransparency( 0 ); - if ( aColor != aFont.GetFillColor() ) - { - if( aFont.IsTransparent() ) - aColor = Color( COL_TRANSPARENT ); - aFont.SetFillColor( aColor ); - mpImpl->mpTextEngine->maFont = aFont; - } - } - - mpImpl->mpTextEngine->ImpPaint( pOut, rStartPos, pPaintArea, pPaintRange, pSelection ); -} - -void TextView::Paint( const Rectangle& rRect ) -{ - ImpPaint( rRect, sal_False ); -} - -void TextView::ImpPaint( const Rectangle& rRect, sal_Bool bUseVirtDev ) -{ - if ( !mpImpl->mpTextEngine->GetUpdateMode() || mpImpl->mpTextEngine->IsInUndo() ) - return; - - TextSelection *pDrawSelection = NULL; - if ( !mpImpl->mbHighlightSelection && mpImpl->maSelection.HasRange() ) - pDrawSelection = &mpImpl->maSelection; - - if ( bUseVirtDev ) - { - VirtualDevice* pVDev = GetVirtualDevice(); - - const Color& rBackgroundColor = mpImpl->mpWindow->GetBackground().GetColor(); - if ( pVDev->GetFillColor() != rBackgroundColor ) - pVDev->SetFillColor( rBackgroundColor ); - if ( pVDev->GetBackground().GetColor() != rBackgroundColor ) - pVDev->SetBackground( rBackgroundColor ); - - sal_Bool bVDevValid = sal_True; - Size aOutSz( pVDev->GetOutputSizePixel() ); - if ( ( aOutSz.Width() < rRect.GetWidth() ) || - ( aOutSz.Height() < rRect.GetHeight() ) ) - { - bVDevValid = pVDev->SetOutputSizePixel( rRect.GetSize() ); - } - else - { - // Das VirtDev kann bei einem Resize sehr gross werden => - // irgendwann mal kleiner machen! - if ( ( aOutSz.Height() > ( rRect.GetHeight() + 20 ) ) || - ( aOutSz.Width() > ( rRect.GetWidth() + 20 ) ) ) - { - bVDevValid = pVDev->SetOutputSizePixel( rRect.GetSize() ); - } - else - { - pVDev->Erase(); - } - } - if ( !bVDevValid ) - { - ImpPaint( rRect, sal_False /* ohne VDev */ ); - return; - } - - Rectangle aTmpRec( Point( 0, 0 ), rRect.GetSize() ); - - Point aDocPos( mpImpl->maStartDocPos.X(), mpImpl->maStartDocPos.Y() + rRect.Top() ); - Point aStartPos = ImpGetOutputStartPos( aDocPos ); - ImpPaint( pVDev, aStartPos, &aTmpRec, NULL, pDrawSelection ); - mpImpl->mpWindow->DrawOutDev( rRect.TopLeft(), rRect.GetSize(), - Point(0,0), rRect.GetSize(), *pVDev ); -// ShowSelection(); - if ( mpImpl->mbHighlightSelection ) - ImpHighlight( mpImpl->maSelection ); - } - else - { - Point aStartPos = ImpGetOutputStartPos( mpImpl->maStartDocPos ); - ImpPaint( mpImpl->mpWindow, aStartPos, &rRect, NULL, pDrawSelection ); - -// ShowSelection(); - if ( mpImpl->mbHighlightSelection ) - ImpHighlight( mpImpl->maSelection ); - } -} - -void TextView::ImpHighlight( const TextSelection& rSel ) -{ - TextSelection aSel( rSel ); - aSel.Justify(); - if ( aSel.HasRange() && !mpImpl->mpTextEngine->IsInUndo() && mpImpl->mpTextEngine->GetUpdateMode() ) - { - mpImpl->mpCursor->Hide(); - - DBG_ASSERT( !mpImpl->mpTextEngine->mpIdleFormatter->IsActive(), "ImpHighlight: Not formatted!" ); - - Rectangle aVisArea( mpImpl->maStartDocPos, mpImpl->mpWindow->GetOutputSizePixel() ); - long nY = 0; - sal_uLong nStartPara = aSel.GetStart().GetPara(); - sal_uLong nEndPara = aSel.GetEnd().GetPara(); - for ( sal_uLong nPara = 0; nPara <= nEndPara; nPara++ ) - { - long nParaHeight = (long)mpImpl->mpTextEngine->CalcParaHeight( nPara ); - if ( ( nPara >= nStartPara ) && ( ( nY + nParaHeight ) > aVisArea.Top() ) ) - { - TEParaPortion* pTEParaPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( nPara ); - sal_uInt16 nStartLine = 0; - sal_uInt16 nEndLine = pTEParaPortion->GetLines().size() -1; - if ( nPara == nStartPara ) - nStartLine = pTEParaPortion->GetLineNumber( aSel.GetStart().GetIndex(), sal_False ); - if ( nPara == nEndPara ) - nEndLine = pTEParaPortion->GetLineNumber( aSel.GetEnd().GetIndex(), sal_True ); - - // ueber die Zeilen iterieren.... - for ( sal_uInt16 nLine = nStartLine; nLine <= nEndLine; nLine++ ) - { - TextLine* pLine = pTEParaPortion->GetLines()[ nLine ]; - sal_uInt16 nStartIndex = pLine->GetStart(); - sal_uInt16 nEndIndex = pLine->GetEnd(); - if ( ( nPara == nStartPara ) && ( nLine == nStartLine ) ) - nStartIndex = aSel.GetStart().GetIndex(); - if ( ( nPara == nEndPara ) && ( nLine == nEndLine ) ) - nEndIndex = aSel.GetEnd().GetIndex(); - - // Kann passieren, wenn am Anfang einer umgebrochenen Zeile. - if ( nEndIndex < nStartIndex ) - nEndIndex = nStartIndex; - - Rectangle aTmpRec( mpImpl->mpTextEngine->GetEditCursor( TextPaM( nPara, nStartIndex ), sal_False ) ); - aTmpRec.Top() += nY; - aTmpRec.Bottom() += nY; - Point aTopLeft( aTmpRec.TopLeft() ); - - aTmpRec = mpImpl->mpTextEngine->GetEditCursor( TextPaM( nPara, nEndIndex ), sal_True ); - aTmpRec.Top() += nY; - aTmpRec.Bottom() += nY; - Point aBottomRight( aTmpRec.BottomRight() ); - aBottomRight.X()--; - - // Nur Painten, wenn im sichtbaren Bereich... - if ( ( aTopLeft.X() < aBottomRight.X() ) && ( aBottomRight.Y() >= aVisArea.Top() ) ) - { - Point aPnt1( GetWindowPos( aTopLeft ) ); - Point aPnt2( GetWindowPos( aBottomRight ) ); - - Rectangle aRect( aPnt1, aPnt2 ); - mpImpl->mpWindow->Invert( aRect ); - } - } - } - nY += nParaHeight; - - if ( nY >= aVisArea.Bottom() ) - break; - } - } -} - -void TextView::ImpSetSelection( const TextSelection& rSelection ) -{ - if ( rSelection != mpImpl->maSelection ) - { - mpImpl->maSelection = rSelection; - mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_VIEWSELECTIONCHANGED ) ); - } -} - -void TextView::ShowSelection() -{ - ImpShowHideSelection( sal_True ); -} - -void TextView::HideSelection() -{ - ImpShowHideSelection( sal_False ); -} - -void TextView::ShowSelection( const TextSelection& rRange ) -{ - ImpShowHideSelection( sal_True, &rRange ); -} - -void TextView::ImpShowHideSelection( sal_Bool bShow, const TextSelection* pRange ) -{ - const TextSelection* pRangeOrSelection = pRange ? pRange : &mpImpl->maSelection; - - if ( pRangeOrSelection->HasRange() ) - { - if ( mpImpl->mbHighlightSelection ) - { - ImpHighlight( *pRangeOrSelection ); - } - else - { - if( mpImpl->mpWindow->IsPaintTransparent() ) - mpImpl->mpWindow->Invalidate(); - else - { - Rectangle aOutArea( Point( 0, 0 ), mpImpl->mpWindow->GetOutputSizePixel() ); - Point aStartPos( ImpGetOutputStartPos( mpImpl->maStartDocPos ) ); - TextSelection aRange( *pRangeOrSelection ); - aRange.Justify(); - sal_Bool bVisCursor = mpImpl->mpCursor->IsVisible(); - mpImpl->mpCursor->Hide(); - ImpPaint( mpImpl->mpWindow, aStartPos, &aOutArea, &aRange, bShow ? &mpImpl->maSelection : NULL ); - if ( bVisCursor ) - mpImpl->mpCursor->Show(); - } - } - } -} - -VirtualDevice* TextView::GetVirtualDevice() -{ - if ( !mpImpl->mpVirtDev ) - { - mpImpl->mpVirtDev = new VirtualDevice; - mpImpl->mpVirtDev->SetLineColor(); - } - return mpImpl->mpVirtDev; -} - -void TextView::EraseVirtualDevice() -{ - delete mpImpl->mpVirtDev; - mpImpl->mpVirtDev = 0; -} - -sal_Bool TextView::KeyInput( const KeyEvent& rKeyEvent ) -{ - sal_Bool bDone = sal_True; - sal_Bool bModified = sal_False; - sal_Bool bMoved = sal_False; - sal_Bool bEndKey = sal_False; // spezielle CursorPosition - sal_Bool bAllowIdle = sal_True; - - // Um zu pruefen ob durch irgendeine Aktion mModified, das lokale - // bModified wird z.B. bei Cut/Paste nicht gesetzt, weil dort an anderen - // Stellen das updaten erfolgt. - sal_Bool bWasModified = mpImpl->mpTextEngine->IsModified(); - mpImpl->mpTextEngine->SetModified( sal_False ); - - TextSelection aCurSel( mpImpl->maSelection ); - TextSelection aOldSel( aCurSel ); - - sal_uInt16 nCode = rKeyEvent.GetKeyCode().GetCode(); - KeyFuncType eFunc = rKeyEvent.GetKeyCode().GetFunction(); - if ( eFunc != KEYFUNC_DONTKNOW ) - { - switch ( eFunc ) - { - case KEYFUNC_CUT: - { - if ( !mpImpl->mbReadOnly ) - Cut(); - } - break; - case KEYFUNC_COPY: - { - Copy(); - } - break; - case KEYFUNC_PASTE: - { - if ( !mpImpl->mbReadOnly ) - Paste(); - } - break; - case KEYFUNC_UNDO: - { - if ( !mpImpl->mbReadOnly ) - Undo(); - } - break; - case KEYFUNC_REDO: - { - if ( !mpImpl->mbReadOnly ) - Redo(); - } - break; - - default: // wird dann evtl. unten bearbeitet. - eFunc = KEYFUNC_DONTKNOW; - } - } - if ( eFunc == KEYFUNC_DONTKNOW ) - { - switch ( nCode ) - { - case KEY_UP: - case KEY_DOWN: - case KEY_LEFT: - case KEY_RIGHT: - case KEY_HOME: - case KEY_END: - case KEY_PAGEUP: - case KEY_PAGEDOWN: - case com::sun::star::awt::Key::MOVE_WORD_FORWARD: - case com::sun::star::awt::Key::SELECT_WORD_FORWARD: - case com::sun::star::awt::Key::MOVE_WORD_BACKWARD: - case com::sun::star::awt::Key::SELECT_WORD_BACKWARD: - case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE: - case com::sun::star::awt::Key::MOVE_TO_END_OF_LINE: - case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE: - case com::sun::star::awt::Key::SELECT_TO_END_OF_LINE: - case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH: - case com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH: - case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH: - case com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH: - case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT: - case com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT: - case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT: - case com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT: - { - if ( ( !rKeyEvent.GetKeyCode().IsMod2() || ( nCode == KEY_LEFT ) || ( nCode == KEY_RIGHT ) ) - && !( rKeyEvent.GetKeyCode().IsMod1() && ( nCode == KEY_PAGEUP || nCode == KEY_PAGEDOWN ) ) ) - { - aCurSel = ImpMoveCursor( rKeyEvent ); - if ( aCurSel.HasRange() ) { - uno::Reference aSelection(GetWindow()->GetPrimarySelection()); - Copy( aSelection ); - } - bMoved = sal_True; - if ( nCode == KEY_END ) - bEndKey = sal_True; - } - else - bDone = sal_False; - } - break; - case KEY_BACKSPACE: - case KEY_DELETE: - case com::sun::star::awt::Key::DELETE_WORD_BACKWARD: - case com::sun::star::awt::Key::DELETE_WORD_FORWARD: - case com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_LINE: - case com::sun::star::awt::Key::DELETE_TO_END_OF_LINE: - { - if ( !mpImpl->mbReadOnly && !rKeyEvent.GetKeyCode().IsMod2() ) - { - sal_uInt8 nDel = ( nCode == KEY_DELETE ) ? DEL_RIGHT : DEL_LEFT; - sal_uInt8 nMode = rKeyEvent.GetKeyCode().IsMod1() ? DELMODE_RESTOFWORD : DELMODE_SIMPLE; - if ( ( nMode == DELMODE_RESTOFWORD ) && rKeyEvent.GetKeyCode().IsShift() ) - nMode = DELMODE_RESTOFCONTENT; - - switch( nCode ) - { - case com::sun::star::awt::Key::DELETE_WORD_BACKWARD: - nDel = DEL_LEFT; - nMode = DELMODE_RESTOFWORD; - break; - case com::sun::star::awt::Key::DELETE_WORD_FORWARD: - nDel = DEL_RIGHT; - nMode = DELMODE_RESTOFWORD; - break; - case com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_LINE: - nDel = DEL_LEFT; - nMode = DELMODE_RESTOFCONTENT; - break; - case com::sun::star::awt::Key::DELETE_TO_END_OF_LINE: - nDel = DEL_RIGHT; - nMode = DELMODE_RESTOFCONTENT; - break; - default: break; - } - - mpImpl->mpTextEngine->UndoActionStart(); - if(mpImpl->mbSupportProtectAttribute) - { - //expand selection to include all protected content - if there is any - const TextCharAttrib* pStartAttr = mpImpl->mpTextEngine->FindCharAttrib( - TextPaM(mpImpl->maSelection.GetStart().GetPara(), - mpImpl->maSelection.GetStart().GetIndex()), - TEXTATTR_PROTECTED ); - const TextCharAttrib* pEndAttr = mpImpl->mpTextEngine->FindCharAttrib( - TextPaM(mpImpl->maSelection.GetEnd().GetPara(), - mpImpl->maSelection.GetEnd().GetIndex()), - TEXTATTR_PROTECTED ); - if(pStartAttr && pStartAttr->GetStart() < mpImpl->maSelection.GetStart().GetIndex()) - { - mpImpl->maSelection.GetStart().GetIndex() = pStartAttr->GetStart(); - } - if(pEndAttr && pEndAttr->GetEnd() > mpImpl->maSelection.GetEnd().GetIndex()) - { - mpImpl->maSelection.GetEnd().GetIndex() = pEndAttr->GetEnd(); - } - } - aCurSel = ImpDelete( nDel, nMode ); - mpImpl->mpTextEngine->UndoActionEnd(); - bModified = sal_True; - bAllowIdle = sal_False; - } - else - bDone = sal_False; - } - break; - case KEY_TAB: - { - if ( !mpImpl->mbReadOnly && !rKeyEvent.GetKeyCode().IsShift() && - !rKeyEvent.GetKeyCode().IsMod1() && !rKeyEvent.GetKeyCode().IsMod2() && - ImplCheckTextLen( rtl::OUString('x') ) ) - { - aCurSel = mpImpl->mpTextEngine->ImpInsertText( aCurSel, '\t', !IsInsertMode() ); - bModified = sal_True; - } - else - bDone = sal_False; - } - break; - case KEY_RETURN: - { - // Shift-RETURN darf nicht geschluckt werden, weil dann keine - // mehrzeilige Eingabe in Dialogen/Property-Editor moeglich. - if ( !mpImpl->mbReadOnly && !rKeyEvent.GetKeyCode().IsMod1() && - !rKeyEvent.GetKeyCode().IsMod2() && ImplCheckTextLen( rtl::OUString('x') ) ) - { - mpImpl->mpTextEngine->UndoActionStart(); - aCurSel = mpImpl->mpTextEngine->ImpInsertParaBreak( aCurSel ); - if ( mpImpl->mbAutoIndent ) - { - TextNode* pPrev = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aCurSel.GetEnd().GetPara() - 1 ); - sal_uInt16 n = 0; - while ( ( n < pPrev->GetText().Len() ) && ( - ( pPrev->GetText().GetChar( n ) == ' ' ) || - ( pPrev->GetText().GetChar( n ) == '\t' ) ) ) - { - n++; - } - if ( n ) - aCurSel = mpImpl->mpTextEngine->ImpInsertText( aCurSel, pPrev->GetText().Copy( 0, n ) ); - } - mpImpl->mpTextEngine->UndoActionEnd(); - bModified = sal_True; - } - else - bDone = sal_False; - } - break; - case KEY_INSERT: - { - if ( !mpImpl->mbReadOnly ) - SetInsertMode( !IsInsertMode() ); - } - break; - default: - { - if ( TextEngine::IsSimpleCharInput( rKeyEvent ) ) - { - xub_Unicode nCharCode = rKeyEvent.GetCharCode(); - if ( !mpImpl->mbReadOnly && ImplCheckTextLen( rtl::OUString(nCharCode) ) ) // sonst trotzdem das Zeichen schlucken... - { - aCurSel = mpImpl->mpTextEngine->ImpInsertText( nCharCode, aCurSel, !IsInsertMode(), sal_True ); - bModified = sal_True; - } - } - else - bDone = sal_False; - } - } - } - - if ( aCurSel != aOldSel ) // Check if changed, maybe other method already changed mpImpl->maSelection, don't overwrite that! - ImpSetSelection( aCurSel ); - - mpImpl->mpTextEngine->UpdateSelections(); - - if ( ( nCode != KEY_UP ) && ( nCode != KEY_DOWN ) ) - mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW; - - if ( bModified ) - { - // Idle-Formatter nur, wenn AnyInput. - if ( bAllowIdle && Application::AnyInput( VCL_INPUT_KEYBOARD) ) - mpImpl->mpTextEngine->IdleFormatAndUpdate( this ); - else - mpImpl->mpTextEngine->FormatAndUpdate( this); - } - else if ( bMoved ) - { - // Selection wird jetzt gezielt in ImpMoveCursor gemalt. - ImpShowCursor( mpImpl->mbAutoScroll, sal_True, bEndKey ); - } - - if ( mpImpl->mpTextEngine->IsModified() ) - mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) ); - else if ( bWasModified ) - mpImpl->mpTextEngine->SetModified( sal_True ); - - return bDone; -} - -void TextView::MouseButtonUp( const MouseEvent& rMouseEvent ) -{ - mpImpl->mbClickedInSelection = sal_False; - mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW; - mpImpl->mpSelEngine->SelMouseButtonUp( rMouseEvent ); - if ( rMouseEvent.IsMiddle() && !IsReadOnly() && - ( GetWindow()->GetSettings().GetMouseSettings().GetMiddleButtonAction() == MOUSE_MIDDLE_PASTESELECTION ) ) - { - uno::Reference aSelection(GetWindow()->GetPrimarySelection()); - Paste( aSelection ); - if ( mpImpl->mpTextEngine->IsModified() ) - mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) ); - } - else if ( rMouseEvent.IsLeft() && GetSelection().HasRange() ) - { - uno::Reference aSelection(GetWindow()->GetPrimarySelection()); - Copy( aSelection ); - } -} - -void TextView::MouseButtonDown( const MouseEvent& rMouseEvent ) -{ - mpImpl->mpTextEngine->CheckIdleFormatter(); // Falls schnelles Tippen und MouseButtonDown - mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW; - mpImpl->mbClickedInSelection = IsSelectionAtPoint( rMouseEvent.GetPosPixel() ); - - mpImpl->mpTextEngine->SetActiveView( this ); - - mpImpl->mpSelEngine->SelMouseButtonDown( rMouseEvent ); - - // mbu 20.01.2005 - SelMouseButtonDown() possibly triggers a 'selection changed' - // notification. The appropriate handler could change the current selection, - // which is the case in the MailMerge address block control. To enable select'n'drag - // we need to reevaluate the selection after the notification has been fired. - mpImpl->mbClickedInSelection = IsSelectionAtPoint( rMouseEvent.GetPosPixel() ); - - // Sonderbehandlungen - if ( !rMouseEvent.IsShift() && ( rMouseEvent.GetClicks() >= 2 ) ) - { - if ( rMouseEvent.IsMod2() ) - { - HideSelection(); - ImpSetSelection( mpImpl->maSelection.GetEnd() ); - SetCursorAtPoint( rMouseEvent.GetPosPixel() ); // Wird von SelectionEngine bei MOD2 nicht gesetzt - } - - if ( rMouseEvent.GetClicks() == 2 ) - { - // Wort selektieren - if ( mpImpl->maSelection.GetEnd().GetIndex() < mpImpl->mpTextEngine->GetTextLen( mpImpl->maSelection.GetEnd().GetPara() ) ) - { - HideSelection(); - TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( mpImpl->maSelection.GetEnd().GetPara() ); - uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator(); - i18n::Boundary aBoundary = xBI->getWordBoundary( pNode->GetText(), mpImpl->maSelection.GetEnd().GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True ); - TextSelection aNewSel( mpImpl->maSelection ); - aNewSel.GetStart().GetIndex() = (sal_uInt16)aBoundary.startPos; - aNewSel.GetEnd().GetIndex() = (sal_uInt16)aBoundary.endPos; - if(mpImpl->mbSupportProtectAttribute) - { - //expand selection to include all protected content - if there is any - const TextCharAttrib* pStartAttr = mpImpl->mpTextEngine->FindCharAttrib( - TextPaM(aNewSel.GetStart().GetPara(), - (sal_uInt16)aBoundary.startPos), - TEXTATTR_PROTECTED ); - const TextCharAttrib* pEndAttr = mpImpl->mpTextEngine->FindCharAttrib( - TextPaM(aNewSel.GetEnd().GetPara(), - (sal_uInt16)aBoundary.endPos), - TEXTATTR_PROTECTED ); - if(pStartAttr && pStartAttr->GetStart() < aNewSel.GetStart().GetIndex()) - { - aNewSel.GetStart().GetIndex() = pStartAttr->GetStart(); - } - if(pEndAttr && pEndAttr->GetEnd() > aNewSel.GetEnd().GetIndex()) - { - aNewSel.GetEnd().GetIndex() = pEndAttr->GetEnd(); - } - } - ImpSetSelection( aNewSel ); - ShowSelection(); - ShowCursor( sal_True, sal_True ); - } - } - else if ( rMouseEvent.GetClicks() == 3 ) - { - // Absatz selektieren - if ( mpImpl->maSelection.GetStart().GetIndex() || ( mpImpl->maSelection.GetEnd().GetIndex() < mpImpl->mpTextEngine->GetTextLen( mpImpl->maSelection.GetEnd().GetPara() ) ) ) - { - HideSelection(); - TextSelection aNewSel( mpImpl->maSelection ); - aNewSel.GetStart().GetIndex() = 0; - aNewSel.GetEnd().GetIndex() = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( mpImpl->maSelection.GetEnd().GetPara() )->GetText().Len(); - ImpSetSelection( aNewSel ); - ShowSelection(); - ShowCursor( sal_True, sal_True ); - } - } - } -} - - -void TextView::MouseMove( const MouseEvent& rMouseEvent ) -{ - mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW; - mpImpl->mpSelEngine->SelMouseMove( rMouseEvent ); -} - -void TextView::Command( const CommandEvent& rCEvt ) -{ - mpImpl->mpTextEngine->CheckIdleFormatter(); // Falls schnelles Tippen und MouseButtonDown - mpImpl->mpTextEngine->SetActiveView( this ); - - if ( rCEvt.GetCommand() == COMMAND_STARTEXTTEXTINPUT ) - { - DeleteSelected(); - delete mpImpl->mpTextEngine->mpIMEInfos; - TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( GetSelection().GetEnd().GetPara() ); - mpImpl->mpTextEngine->mpIMEInfos = new TEIMEInfos( GetSelection().GetEnd(), pNode->GetText().Copy( GetSelection().GetEnd().GetIndex() ) ); - mpImpl->mpTextEngine->mpIMEInfos->bWasCursorOverwrite = !IsInsertMode(); - } - else if ( rCEvt.GetCommand() == COMMAND_ENDEXTTEXTINPUT ) - { - DBG_ASSERT( mpImpl->mpTextEngine->mpIMEInfos, "COMMAND_ENDEXTTEXTINPUT => Kein Start ?" ); - if( mpImpl->mpTextEngine->mpIMEInfos ) - { - TEParaPortion* pPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetPara() ); - pPortion->MarkSelectionInvalid( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetIndex(), 0 ); - - sal_Bool bInsertMode = !mpImpl->mpTextEngine->mpIMEInfos->bWasCursorOverwrite; - - delete mpImpl->mpTextEngine->mpIMEInfos; - mpImpl->mpTextEngine->mpIMEInfos = NULL; - - mpImpl->mpTextEngine->FormatAndUpdate( this ); - - SetInsertMode( bInsertMode ); - - if ( mpImpl->mpTextEngine->IsModified() ) - mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) ); - } - } - else if ( rCEvt.GetCommand() == COMMAND_EXTTEXTINPUT ) - { - DBG_ASSERT( mpImpl->mpTextEngine->mpIMEInfos, "COMMAND_EXTTEXTINPUT => Kein Start ?" ); - if( mpImpl->mpTextEngine->mpIMEInfos ) - { - const CommandExtTextInputData* pData = rCEvt.GetExtTextInputData(); - - if ( !pData->IsOnlyCursorChanged() ) - { - TextSelection aSelect( mpImpl->mpTextEngine->mpIMEInfos->aPos ); - aSelect.GetEnd().GetIndex() = aSelect.GetEnd().GetIndex() + mpImpl->mpTextEngine->mpIMEInfos->nLen; - aSelect = mpImpl->mpTextEngine->ImpDeleteText( aSelect ); - aSelect = mpImpl->mpTextEngine->ImpInsertText( aSelect, pData->GetText() ); - - if ( mpImpl->mpTextEngine->mpIMEInfos->bWasCursorOverwrite ) - { - sal_uInt16 nOldIMETextLen = mpImpl->mpTextEngine->mpIMEInfos->nLen; - sal_uInt16 nNewIMETextLen = pData->GetText().Len(); - - if ( ( nOldIMETextLen > nNewIMETextLen ) && - ( nNewIMETextLen < mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.Len() ) ) - { - // restore old characters - sal_uInt16 nRestore = nOldIMETextLen - nNewIMETextLen; - TextPaM aPaM( mpImpl->mpTextEngine->mpIMEInfos->aPos ); - aPaM.GetIndex() = aPaM.GetIndex() + nNewIMETextLen; - mpImpl->mpTextEngine->ImpInsertText( aPaM, mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.Copy( nNewIMETextLen, nRestore ) ); - } - else if ( ( nOldIMETextLen < nNewIMETextLen ) && - ( nOldIMETextLen < mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.Len() ) ) - { - // overwrite - sal_uInt16 nOverwrite = nNewIMETextLen - nOldIMETextLen; - if ( ( nOldIMETextLen + nOverwrite ) > mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.Len() ) - nOverwrite = mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.Len() - nOldIMETextLen; - DBG_ASSERT( nOverwrite && (nOverwrite < 0xFF00), "IME Overwrite?!" ); - TextPaM aPaM( mpImpl->mpTextEngine->mpIMEInfos->aPos ); - aPaM.GetIndex() = aPaM.GetIndex() + nNewIMETextLen; - TextSelection aSel( aPaM ); - aSel.GetEnd().GetIndex() = - aSel.GetEnd().GetIndex() + nOverwrite; - mpImpl->mpTextEngine->ImpDeleteText( aSel ); - } - } - - if ( pData->GetTextAttr() ) - { - mpImpl->mpTextEngine->mpIMEInfos->CopyAttribs( pData->GetTextAttr(), pData->GetText().Len() ); - mpImpl->mpTextEngine->mpIMEInfos->bCursor = pData->IsCursorVisible(); - } - else - { - mpImpl->mpTextEngine->mpIMEInfos->DestroyAttribs(); - } - - TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetPara() ); - pPPortion->MarkSelectionInvalid( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetIndex(), 0 ); - mpImpl->mpTextEngine->FormatAndUpdate( this ); - } - - TextSelection aNewSel = TextPaM( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetPara(), mpImpl->mpTextEngine->mpIMEInfos->aPos.GetIndex()+pData->GetCursorPos() ); - SetSelection( aNewSel ); - SetInsertMode( !pData->IsCursorOverwrite() ); - - if ( pData->IsCursorVisible() ) - ShowCursor(); - else - HideCursor(); - } - } - else if ( rCEvt.GetCommand() == COMMAND_CURSORPOS ) - { - if ( mpImpl->mpTextEngine->mpIMEInfos && mpImpl->mpTextEngine->mpIMEInfos->nLen ) - { - TextPaM aPaM( GetSelection().GetEnd() ); - Rectangle aR1 = mpImpl->mpTextEngine->PaMtoEditCursor( aPaM ); - - sal_uInt16 nInputEnd = mpImpl->mpTextEngine->mpIMEInfos->aPos.GetIndex() + mpImpl->mpTextEngine->mpIMEInfos->nLen; - - if ( !mpImpl->mpTextEngine->IsFormatted() ) - mpImpl->mpTextEngine->FormatDoc(); - - TEParaPortion* pParaPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() ); - sal_uInt16 nLine = pParaPortion->GetLineNumber( aPaM.GetIndex(), sal_True ); - TextLine* pLine = pParaPortion->GetLines()[ nLine ]; - if ( pLine && ( nInputEnd > pLine->GetEnd() ) ) - nInputEnd = pLine->GetEnd(); - Rectangle aR2 = mpImpl->mpTextEngine->PaMtoEditCursor( TextPaM( aPaM.GetPara(), nInputEnd ) ); - - long nWidth = aR2.Left()-aR1.Right(); - aR1.Move( -GetStartDocPos().X(), -GetStartDocPos().Y() ); - GetWindow()->SetCursorRect( &aR1, nWidth ); - } - else - { - GetWindow()->SetCursorRect(); - } - } - else - { - mpImpl->mpSelEngine->Command( rCEvt ); - } -} - -void TextView::ShowCursor( sal_Bool bGotoCursor, sal_Bool bForceVisCursor ) -{ - // Die Einstellung hat mehr Gewicht: - if ( !mpImpl->mbAutoScroll ) - bGotoCursor = sal_False; - ImpShowCursor( bGotoCursor, bForceVisCursor, sal_False ); -} - -void TextView::HideCursor() -{ - mpImpl->mpCursor->Hide(); -} - -void TextView::Scroll( long ndX, long ndY ) -{ - DBG_ASSERT( mpImpl->mpTextEngine->IsFormatted(), "Scroll: Nicht formatiert!" ); - - if ( !ndX && !ndY ) - return; - - Point aNewStartPos( mpImpl->maStartDocPos ); - - // Vertical: - aNewStartPos.Y() -= ndY; - if ( aNewStartPos.Y() < 0 ) - aNewStartPos.Y() = 0; - - // Horizontal: - aNewStartPos.X() -= ndX; - if ( aNewStartPos.X() < 0 ) - aNewStartPos.X() = 0; - - long nDiffX = mpImpl->maStartDocPos.X() - aNewStartPos.X(); - long nDiffY = mpImpl->maStartDocPos.Y() - aNewStartPos.Y(); - - if ( nDiffX || nDiffY ) - { - sal_Bool bVisCursor = mpImpl->mpCursor->IsVisible(); - mpImpl->mpCursor->Hide(); - mpImpl->mpWindow->Update(); - mpImpl->maStartDocPos = aNewStartPos; - - if ( mpImpl->mpTextEngine->IsRightToLeft() ) - nDiffX = -nDiffX; - mpImpl->mpWindow->Scroll( nDiffX, nDiffY ); - mpImpl->mpWindow->Update(); - mpImpl->mpCursor->SetPos( mpImpl->mpCursor->GetPos() + Point( nDiffX, nDiffY ) ); - if ( bVisCursor && !mpImpl->mbReadOnly ) - mpImpl->mpCursor->Show(); - } - - mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_VIEWSCROLLED ) ); -} - -void TextView::Undo() -{ - mpImpl->mpTextEngine->SetActiveView( this ); - mpImpl->mpTextEngine->GetUndoManager().Undo(); -} - -void TextView::Redo() -{ - mpImpl->mpTextEngine->SetActiveView( this ); - mpImpl->mpTextEngine->GetUndoManager().Redo(); -} - -void TextView::Cut() -{ - mpImpl->mpTextEngine->UndoActionStart(); - Copy(); - DeleteSelected(); - mpImpl->mpTextEngine->UndoActionEnd(); -} - -void TextView::Copy( uno::Reference< datatransfer::clipboard::XClipboard >& rxClipboard ) -{ - if ( rxClipboard.is() ) - { - TETextDataObject* pDataObj = new TETextDataObject( GetSelected() ); - - if ( mpImpl->mpTextEngine->HasAttrib( TEXTATTR_HYPERLINK ) ) // Dann auch als HTML - mpImpl->mpTextEngine->Write( pDataObj->GetHTMLStream(), &mpImpl->maSelection, sal_True ); - - const sal_uInt32 nRef = Application::ReleaseSolarMutex(); - - try - { - rxClipboard->setContents( pDataObj, NULL ); - - uno::Reference< datatransfer::clipboard::XFlushableClipboard > xFlushableClipboard( rxClipboard, uno::UNO_QUERY ); - if( xFlushableClipboard.is() ) - xFlushableClipboard->flushClipboard(); - } - catch( const ::com::sun::star::uno::Exception& ) - { - } - - Application::AcquireSolarMutex( nRef ); - } -} - -void TextView::Copy() -{ - uno::Reference aClipboard(GetWindow()->GetClipboard()); - Copy( aClipboard ); -} - -void TextView::Paste( uno::Reference< datatransfer::clipboard::XClipboard >& rxClipboard ) -{ - if ( rxClipboard.is() ) - { - uno::Reference< datatransfer::XTransferable > xDataObj; - - const sal_uInt32 nRef = Application::ReleaseSolarMutex(); - - try - { - xDataObj = rxClipboard->getContents(); - } - catch( const ::com::sun::star::uno::Exception& ) - { - } - - Application::AcquireSolarMutex( nRef ); - - if ( xDataObj.is() ) - { - datatransfer::DataFlavor aFlavor; - SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor ); - if ( xDataObj->isDataFlavorSupported( aFlavor ) ) - { - try - { - uno::Any aData = xDataObj->getTransferData( aFlavor ); - ::rtl::OUString aText; - aData >>= aText; - bool bWasTruncated = false; - if( mpImpl->mpTextEngine->GetMaxTextLen() != 0 ) - bWasTruncated = ImplTruncateNewText( aText ); - InsertNewText( aText, sal_False ); - mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) ); - - if( bWasTruncated ) - Edit::ShowTruncationWarning( mpImpl->mpWindow ); - } - catch( const ::com::sun::star::datatransfer::UnsupportedFlavorException& ) - { - } - } - } - } -} - -void TextView::Paste() -{ - uno::Reference aClipboard(GetWindow()->GetClipboard()); - Paste( aClipboard ); -} - -String TextView::GetSelected() -{ - return GetSelected( GetSystemLineEnd() ); -} - -String TextView::GetSelected( LineEnd aSeparator ) -{ - return mpImpl->mpTextEngine->GetText( mpImpl->maSelection, aSeparator ); -} - -void TextView::SetInsertMode( sal_Bool bInsert ) -{ - if ( mpImpl->mbInsertMode != bInsert ) - { - mpImpl->mbInsertMode = bInsert; - ShowCursor( mpImpl->mbAutoScroll, sal_False ); - } -} - -void TextView::SetReadOnly( sal_Bool bReadOnly ) -{ - if ( mpImpl->mbReadOnly != bReadOnly ) - { - mpImpl->mbReadOnly = bReadOnly; - if ( !mpImpl->mbReadOnly ) - ShowCursor( mpImpl->mbAutoScroll, sal_False ); - else - HideCursor(); - - GetWindow()->SetInputContext( InputContext( mpImpl->mpTextEngine->GetFont(), bReadOnly ? INPUTCONTEXT_TEXT|INPUTCONTEXT_EXTTEXTINPUT : 0 ) ); - } -} - -TextSelection TextView::ImpMoveCursor( const KeyEvent& rKeyEvent ) -{ - // Eigentlich nur bei Up/Down noetig, aber was solls. - mpImpl->mpTextEngine->CheckIdleFormatter(); - - TextPaM aPaM( mpImpl->maSelection.GetEnd() ); - TextPaM aOldEnd( aPaM ); - - TextDirectionality eTextDirection = TextDirectionality_LeftToRight_TopToBottom; - if ( mpImpl->mpTextEngine->IsRightToLeft() ) - eTextDirection = TextDirectionality_RightToLeft_TopToBottom; - - KeyEvent aTranslatedKeyEvent = rKeyEvent.LogicalTextDirectionality( eTextDirection ); - - sal_Bool bCtrl = aTranslatedKeyEvent.GetKeyCode().IsMod1() ? sal_True : sal_False; - sal_uInt16 nCode = aTranslatedKeyEvent.GetKeyCode().GetCode(); - - bool bSelect = aTranslatedKeyEvent.GetKeyCode().IsShift(); - switch ( nCode ) - { - case KEY_UP: aPaM = CursorUp( aPaM ); - break; - case KEY_DOWN: aPaM = CursorDown( aPaM ); - break; - case KEY_HOME: aPaM = bCtrl ? CursorStartOfDoc() : CursorStartOfLine( aPaM ); - break; - case KEY_END: aPaM = bCtrl ? CursorEndOfDoc() : CursorEndOfLine( aPaM ); - break; - case KEY_PAGEUP: aPaM = bCtrl ? CursorStartOfDoc() : PageUp( aPaM ); - break; - case KEY_PAGEDOWN: aPaM = bCtrl ? CursorEndOfDoc() : PageDown( aPaM ); - break; - case KEY_LEFT: aPaM = bCtrl ? CursorWordLeft( aPaM ) : CursorLeft( aPaM, aTranslatedKeyEvent.GetKeyCode().IsMod2() ? (sal_uInt16)i18n::CharacterIteratorMode::SKIPCHARACTER : (sal_uInt16)i18n::CharacterIteratorMode::SKIPCELL ); - break; - case KEY_RIGHT: aPaM = bCtrl ? CursorWordRight( aPaM ) : CursorRight( aPaM, aTranslatedKeyEvent.GetKeyCode().IsMod2() ? (sal_uInt16)i18n::CharacterIteratorMode::SKIPCHARACTER : (sal_uInt16)i18n::CharacterIteratorMode::SKIPCELL ); - break; - case com::sun::star::awt::Key::SELECT_WORD_FORWARD: - bSelect = true; // fallthrough intentional - case com::sun::star::awt::Key::MOVE_WORD_FORWARD: - aPaM = CursorWordRight( aPaM ); - break; - case com::sun::star::awt::Key::SELECT_WORD_BACKWARD: - bSelect = true; // fallthrough intentional - case com::sun::star::awt::Key::MOVE_WORD_BACKWARD: - aPaM = CursorWordLeft( aPaM ); - break; - case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE: - bSelect = true; // fallthrough intentional - case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE: - aPaM = CursorStartOfLine( aPaM ); - break; - case com::sun::star::awt::Key::SELECT_TO_END_OF_LINE: - bSelect = true; // fallthrough intentional - case com::sun::star::awt::Key::MOVE_TO_END_OF_LINE: - aPaM = CursorEndOfLine( aPaM ); - break; - case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH: - bSelect = true; // falltthrough intentional - case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH: - aPaM = CursorStartOfParagraph( aPaM ); - break; - case com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH: - bSelect = true; // falltthrough intentional - case com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH: - aPaM = CursorEndOfParagraph( aPaM ); - break; - case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT: - bSelect = true; // falltthrough intentional - case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT: - aPaM = CursorStartOfDoc(); - break; - case com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT: - bSelect = true; // falltthrough intentional - case com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT: - aPaM = CursorEndOfDoc(); - break; - } - - // Bewirkt evtl. ein CreateAnchor oder Deselection all - mpImpl->mpSelEngine->CursorPosChanging( bSelect, aTranslatedKeyEvent.GetKeyCode().IsMod1() ); - - if ( aOldEnd != aPaM ) - { - mpImpl->mpTextEngine->CursorMoved( aOldEnd.GetPara() ); - - TextSelection aNewSelection( mpImpl->maSelection ); - aNewSelection.GetEnd() = aPaM; - if ( bSelect ) - { - // Dann wird die Selektion erweitert... - ImpSetSelection( aNewSelection ); - ShowSelection( TextSelection( aOldEnd, aPaM ) ); - } - else - { - aNewSelection.GetStart() = aPaM; - ImpSetSelection( aNewSelection ); - } - } - - return mpImpl->maSelection; -} - -void TextView::InsertText( const XubString& rStr, sal_Bool bSelect ) -{ - InsertNewText( rStr, bSelect ); -} - -void TextView::InsertNewText( const rtl::OUString& rStr, sal_Bool bSelect ) -{ -// HideSelection(); - mpImpl->mpTextEngine->UndoActionStart(); - - /* #i87633# - break inserted text into chunks that fit into the underlying String - based API (which has a maximum length of 65534 elements - - note: this will of course still cause problems for lines longer than those - 65534 elements, but those cases will hopefully be few. - In the long run someone should switch the TextEngine to OUString instead of String - */ - sal_Int32 nLen = rStr.getLength(); - sal_Int32 nPos = 0; - do - { - sal_Int32 nChunkLen = nLen > 65534 ? 65534 : nLen; - String aChunk( rStr.copy( nPos, nChunkLen ) ); - - TextSelection aNewSel( mpImpl->maSelection ); - - TextPaM aPaM = mpImpl->mpTextEngine->ImpInsertText( mpImpl->maSelection, aChunk ); - - if ( bSelect ) - { - aNewSel.Justify(); - aNewSel.GetEnd() = aPaM; - } - else - { - aNewSel = aPaM; - } - - ImpSetSelection( aNewSel ); - nLen -= nChunkLen; - nPos += nChunkLen; - } - while( nLen ); - - mpImpl->mpTextEngine->UndoActionEnd(); - - mpImpl->mpTextEngine->FormatAndUpdate( this ); -} - -TextPaM TextView::CursorLeft( const TextPaM& rPaM, sal_uInt16 nCharacterIteratorMode ) -{ - TextPaM aPaM( rPaM ); - - if ( aPaM.GetIndex() ) - { - TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() ); - uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator(); - sal_Int32 nCount = 1; - aPaM.GetIndex() = (sal_uInt16)xBI->previousCharacters( pNode->GetText(), aPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), nCharacterIteratorMode, nCount, nCount ); - } - else if ( aPaM.GetPara() ) - { - aPaM.GetPara()--; - TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() ); - aPaM.GetIndex() = pNode->GetText().Len(); - } - return aPaM; -} - -TextPaM TextView::CursorRight( const TextPaM& rPaM, sal_uInt16 nCharacterIteratorMode ) -{ - TextPaM aPaM( rPaM ); - - TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() ); - if ( aPaM.GetIndex() < pNode->GetText().Len() ) - { - uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator(); - sal_Int32 nCount = 1; - aPaM.GetIndex() = (sal_uInt16)xBI->nextCharacters( pNode->GetText(), aPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), nCharacterIteratorMode, nCount, nCount ); - } - else if ( aPaM.GetPara() < ( mpImpl->mpTextEngine->mpDoc->GetNodes().Count()-1) ) - { - aPaM.GetPara()++; - aPaM.GetIndex() = 0; - } - - return aPaM; -} - - -TextPaM TextView::CursorWordLeft( const TextPaM& rPaM ) -{ - TextPaM aPaM( rPaM ); - - if ( aPaM.GetIndex() ) - { - TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() ); - uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator(); - i18n::Boundary aBoundary = xBI->getWordBoundary( pNode->GetText(), rPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True ); - if ( aBoundary.startPos >= rPaM.GetIndex() ) - aBoundary = xBI->previousWord( pNode->GetText(), rPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES ); - aPaM.GetIndex() = ( aBoundary.startPos != -1 ) ? (sal_uInt16)aBoundary.startPos : 0; - } - else if ( aPaM.GetPara() ) - { - aPaM.GetPara()--; - TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() ); - aPaM.GetIndex() = pNode->GetText().Len(); - } - return aPaM; -} - - -TextPaM TextView::CursorWordRight( const TextPaM& rPaM ) -{ - TextPaM aPaM( rPaM ); - - TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() ); - if ( aPaM.GetIndex() < pNode->GetText().Len() ) - { - uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator(); - i18n::Boundary aBoundary = xBI->nextWord( pNode->GetText(), aPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES ); - aPaM.GetIndex() = (sal_uInt16)aBoundary.startPos; - } - else if ( aPaM.GetPara() < ( mpImpl->mpTextEngine->mpDoc->GetNodes().Count()-1) ) - { - aPaM.GetPara()++; - aPaM.GetIndex() = 0; - } - - return aPaM; -} - -TextPaM TextView::ImpDelete( sal_uInt8 nMode, sal_uInt8 nDelMode ) -{ - if ( mpImpl->maSelection.HasRange() ) // dann nur Sel. loeschen - return mpImpl->mpTextEngine->ImpDeleteText( mpImpl->maSelection ); - - TextPaM aStartPaM = mpImpl->maSelection.GetStart(); - TextPaM aEndPaM = aStartPaM; - if ( nMode == DEL_LEFT ) - { - if ( nDelMode == DELMODE_SIMPLE ) - { - aEndPaM = CursorLeft( aEndPaM, (sal_uInt16)i18n::CharacterIteratorMode::SKIPCHARACTER ); - } - else if ( nDelMode == DELMODE_RESTOFWORD ) - { - TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aEndPaM.GetPara() ); - uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator(); - i18n::Boundary aBoundary = xBI->getWordBoundary( pNode->GetText(), mpImpl->maSelection.GetEnd().GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True ); - if ( aBoundary.startPos == mpImpl->maSelection.GetEnd().GetIndex() ) - aBoundary = xBI->previousWord( pNode->GetText(), mpImpl->maSelection.GetEnd().GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES ); - // #i63506# startPos is -1 when the paragraph starts with a tab - aEndPaM.GetIndex() = (aBoundary.startPos >= 0) ? (sal_uInt16)aBoundary.startPos : 0; - } - else // DELMODE_RESTOFCONTENT - { - if ( aEndPaM.GetIndex() != 0 ) - aEndPaM.GetIndex() = 0; - else if ( aEndPaM.GetPara() ) - { - // Absatz davor - aEndPaM.GetPara()--; - aEndPaM.GetIndex() = 0; - } - } - } - else - { - if ( nDelMode == DELMODE_SIMPLE ) - { - aEndPaM = CursorRight( aEndPaM, (sal_uInt16)i18n::CharacterIteratorMode::SKIPCELL ); - } - else if ( nDelMode == DELMODE_RESTOFWORD ) - { - TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aEndPaM.GetPara() ); - uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator(); - i18n::Boundary aBoundary = xBI->nextWord( pNode->GetText(), mpImpl->maSelection.GetEnd().GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES ); - aEndPaM.GetIndex() = (sal_uInt16)aBoundary.startPos; - } - else // DELMODE_RESTOFCONTENT - { - TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aEndPaM.GetPara() ); - if ( aEndPaM.GetIndex() < pNode->GetText().Len() ) - aEndPaM.GetIndex() = pNode->GetText().Len(); - else if ( aEndPaM.GetPara() < ( mpImpl->mpTextEngine->mpDoc->GetNodes().Count() - 1 ) ) - { - // Absatz danach - aEndPaM.GetPara()++; - TextNode* pNextNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aEndPaM.GetPara() ); - aEndPaM.GetIndex() = pNextNode->GetText().Len(); - } - } - } - - return mpImpl->mpTextEngine->ImpDeleteText( TextSelection( aStartPaM, aEndPaM ) ); -} - - - -TextPaM TextView::CursorUp( const TextPaM& rPaM ) -{ - TextPaM aPaM( rPaM ); - - long nX; - if ( mpImpl->mnTravelXPos == TRAVEL_X_DONTKNOW ) - { - nX = mpImpl->mpTextEngine->GetEditCursor( rPaM, sal_False ).Left(); - mpImpl->mnTravelXPos = (sal_uInt16)nX+1; - } - else - nX = mpImpl->mnTravelXPos; - - TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() ); - sal_uInt16 nLine = pPPortion->GetLineNumber( rPaM.GetIndex(), sal_False ); - if ( nLine ) // gleicher Absatz - { - sal_uInt16 nCharPos = mpImpl->mpTextEngine->GetCharPos( rPaM.GetPara(), nLine-1, nX ); - aPaM.GetIndex() = nCharPos; - // Wenn davor eine autom.Umgebrochene Zeile, und ich muss genau an das - // Ende dieser Zeile, landet der Cursor in der aktuellen Zeile am Anfang - // Siehe Problem: Letztes Zeichen einer autom.umgebr. Zeile = Cursor - TextLine* pLine = pPPortion->GetLines()[ nLine - 1 ]; - if ( aPaM.GetIndex() && ( aPaM.GetIndex() == pLine->GetEnd() ) ) - aPaM.GetIndex()--; - } - else if ( rPaM.GetPara() ) // vorheriger Absatz - { - aPaM.GetPara()--; - pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() ); - sal_uInt16 nL = pPPortion->GetLines().size() - 1; - sal_uInt16 nCharPos = mpImpl->mpTextEngine->GetCharPos( aPaM.GetPara(), nL, nX+1 ); - aPaM.GetIndex() = nCharPos; - } - - return aPaM; -} - -TextPaM TextView::CursorDown( const TextPaM& rPaM ) -{ - TextPaM aPaM( rPaM ); - - long nX; - if ( mpImpl->mnTravelXPos == TRAVEL_X_DONTKNOW ) - { - nX = mpImpl->mpTextEngine->GetEditCursor( rPaM, sal_False ).Left(); - mpImpl->mnTravelXPos = (sal_uInt16)nX+1; - } - else - nX = mpImpl->mnTravelXPos; - - TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() ); - sal_uInt16 nLine = pPPortion->GetLineNumber( rPaM.GetIndex(), sal_False ); - if ( nLine < ( pPPortion->GetLines().size() - 1 ) ) - { - sal_uInt16 nCharPos = mpImpl->mpTextEngine->GetCharPos( rPaM.GetPara(), nLine+1, nX ); - aPaM.GetIndex() = nCharPos; - - // Sonderbehandlung siehe CursorUp... - TextLine* pLine = pPPortion->GetLines()[ nLine + 1 ]; - if ( ( aPaM.GetIndex() == pLine->GetEnd() ) && ( aPaM.GetIndex() > pLine->GetStart() ) && aPaM.GetIndex() < pPPortion->GetNode()->GetText().Len() ) - aPaM.GetIndex()--; - } - else if ( rPaM.GetPara() < ( mpImpl->mpTextEngine->mpDoc->GetNodes().Count() - 1 ) ) // naechster Absatz - { - aPaM.GetPara()++; - pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() ); - sal_uInt16 nCharPos = mpImpl->mpTextEngine->GetCharPos( aPaM.GetPara(), 0, nX+1 ); - aPaM.GetIndex() = nCharPos; - TextLine* pLine = pPPortion->GetLines().front(); - if ( ( aPaM.GetIndex() == pLine->GetEnd() ) && ( aPaM.GetIndex() > pLine->GetStart() ) && ( pPPortion->GetLines().size() > 1 ) ) - aPaM.GetIndex()--; - } - - return aPaM; -} - -TextPaM TextView::CursorStartOfLine( const TextPaM& rPaM ) -{ - TextPaM aPaM( rPaM ); - - TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() ); - sal_uInt16 nLine = pPPortion->GetLineNumber( aPaM.GetIndex(), sal_False ); - TextLine* pLine = pPPortion->GetLines()[ nLine ]; - aPaM.GetIndex() = pLine->GetStart(); - - return aPaM; -} - -TextPaM TextView::CursorEndOfLine( const TextPaM& rPaM ) -{ - TextPaM aPaM( rPaM ); - - TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() ); - sal_uInt16 nLine = pPPortion->GetLineNumber( aPaM.GetIndex(), sal_False ); - TextLine* pLine = pPPortion->GetLines()[ nLine ]; - aPaM.GetIndex() = pLine->GetEnd(); - - if ( pLine->GetEnd() > pLine->GetStart() ) // Leerzeile - { - xub_Unicode cLastChar = pPPortion->GetNode()->GetText().GetChar((sal_uInt16)(aPaM.GetIndex()-1) ); - if ( ( cLastChar == ' ' ) && ( aPaM.GetIndex() != pPPortion->GetNode()->GetText().Len() ) ) - { - // Bei einem Blank in einer autom. umgebrochenen Zeile macht es Sinn, - // davor zu stehen, da der Anwender hinter das Wort will. - // Wenn diese geaendert wird, Sonderbehandlung fuer Pos1 nach End! - aPaM.GetIndex()--; - } - } - return aPaM; -} - -TextPaM TextView::CursorStartOfParagraph( const TextPaM& rPaM ) -{ - TextPaM aPaM( rPaM ); - aPaM.GetIndex() = 0; - return aPaM; -} - -TextPaM TextView::CursorEndOfParagraph( const TextPaM& rPaM ) -{ - TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( rPaM.GetPara() ); - TextPaM aPaM( rPaM ); - aPaM.GetIndex() = pNode->GetText().Len(); - return aPaM; -} - -TextPaM TextView::CursorStartOfDoc() -{ - TextPaM aPaM( 0, 0 ); - return aPaM; -} - -TextPaM TextView::CursorEndOfDoc() -{ - sal_uLong nNode = mpImpl->mpTextEngine->mpDoc->GetNodes().Count() - 1; - TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( nNode ); - TextPaM aPaM( nNode, pNode->GetText().Len() ); - return aPaM; -} - -TextPaM TextView::PageUp( const TextPaM& rPaM ) -{ - Rectangle aRec = mpImpl->mpTextEngine->PaMtoEditCursor( rPaM ); - Point aTopLeft = aRec.TopLeft(); - aTopLeft.Y() -= mpImpl->mpWindow->GetOutputSizePixel().Height() * 9/10; - aTopLeft.X() += 1; - if ( aTopLeft.Y() < 0 ) - aTopLeft.Y() = 0; - - TextPaM aPaM = mpImpl->mpTextEngine->GetPaM( aTopLeft ); - return aPaM; -} - -TextPaM TextView::PageDown( const TextPaM& rPaM ) -{ - Rectangle aRec = mpImpl->mpTextEngine->PaMtoEditCursor( rPaM ); - Point aBottomRight = aRec.BottomRight(); - aBottomRight.Y() += mpImpl->mpWindow->GetOutputSizePixel().Height() * 9/10; - aBottomRight.X() += 1; - long nHeight = mpImpl->mpTextEngine->GetTextHeight(); - if ( aBottomRight.Y() > nHeight ) - aBottomRight.Y() = nHeight-1; - - TextPaM aPaM = mpImpl->mpTextEngine->GetPaM( aBottomRight ); - return aPaM; -} - -void TextView::ImpShowCursor( sal_Bool bGotoCursor, sal_Bool bForceVisCursor, sal_Bool bSpecial ) -{ - if ( mpImpl->mpTextEngine->IsFormatting() ) - return; - if ( mpImpl->mpTextEngine->GetUpdateMode() == sal_False ) - return; - if ( mpImpl->mpTextEngine->IsInUndo() ) - return; - - mpImpl->mpTextEngine->CheckIdleFormatter(); - if ( !mpImpl->mpTextEngine->IsFormatted() ) - mpImpl->mpTextEngine->FormatAndUpdate( this ); - - - TextPaM aPaM( mpImpl->maSelection.GetEnd() ); - Rectangle aEditCursor = mpImpl->mpTextEngine->PaMtoEditCursor( aPaM, bSpecial ); - - // Remember that we placed the cursor behind the last character of a line - mpImpl->mbCursorAtEndOfLine = false; - if( bSpecial ) - { - TEParaPortion* pParaPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() ); - mpImpl->mbCursorAtEndOfLine = - pParaPortion->GetLineNumber( aPaM.GetIndex(), sal_True ) != pParaPortion->GetLineNumber( aPaM.GetIndex(), sal_False ); - } - - if ( !IsInsertMode() && !mpImpl->maSelection.HasRange() ) - { - TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() ); - if ( pNode->GetText().Len() && ( aPaM.GetIndex() < pNode->GetText().Len() ) ) - { - // If we are behind a portion, and the next portion has other direction, we must change position... - aEditCursor.Left() = aEditCursor.Right() = mpImpl->mpTextEngine->GetEditCursor( aPaM, sal_False, sal_True ).Left(); - - TEParaPortion* pParaPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() ); - - sal_uInt16 nTextPortionStart = 0; - sal_uInt16 nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nTextPortionStart, sal_True ); - TETextPortion* pTextPortion = pParaPortion->GetTextPortions()[ nTextPortion ]; - if ( pTextPortion->GetKind() == PORTIONKIND_TAB ) - { - if ( mpImpl->mpTextEngine->IsRightToLeft() ) - { - - } - aEditCursor.Right() += pTextPortion->GetWidth(); - } - else - { - TextPaM aNext = CursorRight( TextPaM( aPaM.GetPara(), aPaM.GetIndex() ), (sal_uInt16)i18n::CharacterIteratorMode::SKIPCELL ); - aEditCursor.Right() = mpImpl->mpTextEngine->GetEditCursor( aNext, sal_True ).Left(); - } - } - } - - Size aOutSz = mpImpl->mpWindow->GetOutputSizePixel(); - if ( aEditCursor.GetHeight() > aOutSz.Height() ) - aEditCursor.Bottom() = aEditCursor.Top() + aOutSz.Height() - 1; - - aEditCursor.Left() -= 1; - - if ( bGotoCursor - // #i81283# protext maStartDocPos against initialization problems - && aOutSz.Width() && aOutSz.Height() - ) - { - long nVisStartY = mpImpl->maStartDocPos.Y(); - long nVisEndY = mpImpl->maStartDocPos.Y() + aOutSz.Height(); - long nVisStartX = mpImpl->maStartDocPos.X(); - long nVisEndX = mpImpl->maStartDocPos.X() + aOutSz.Width(); - long nMoreX = aOutSz.Width() / 4; - - Point aNewStartPos( mpImpl->maStartDocPos ); - - if ( aEditCursor.Bottom() > nVisEndY ) - { - aNewStartPos.Y() += ( aEditCursor.Bottom() - nVisEndY ); - } - else if ( aEditCursor.Top() < nVisStartY ) - { - aNewStartPos.Y() -= ( nVisStartY - aEditCursor.Top() ); - } - - if ( aEditCursor.Right() >= nVisEndX ) - { - aNewStartPos.X() += ( aEditCursor.Right() - nVisEndX ); - - // Darfs ein bischen mehr sein? - aNewStartPos.X() += nMoreX; - } - else if ( aEditCursor.Left() <= nVisStartX ) - { - aNewStartPos.X() -= ( nVisStartX - aEditCursor.Left() ); - - // Darfs ein bischen mehr sein? - aNewStartPos.X() -= nMoreX; - } - - // X kann durch das 'bischen mehr' falsch sein: -// sal_uLong nMaxTextWidth = mpImpl->mpTextEngine->GetMaxTextWidth(); -// if ( !nMaxTextWidth || ( nMaxTextWidth > 0x7FFFFFFF ) ) -// nMaxTextWidth = 0x7FFFFFFF; -// long nMaxX = (long)nMaxTextWidth - aOutSz.Width(); - long nMaxX = mpImpl->mpTextEngine->CalcTextWidth() - aOutSz.Width(); - if ( nMaxX < 0 ) - nMaxX = 0; - - if ( aNewStartPos.X() < 0 ) - aNewStartPos.X() = 0; - else if ( aNewStartPos.X() > nMaxX ) - aNewStartPos.X() = nMaxX; - - // Y sollte nicht weiter unten als noetig liegen: - long nYMax = mpImpl->mpTextEngine->GetTextHeight() - aOutSz.Height(); - if ( nYMax < 0 ) - nYMax = 0; - if ( aNewStartPos.Y() > nYMax ) - aNewStartPos.Y() = nYMax; - - if ( aNewStartPos != mpImpl->maStartDocPos ) - Scroll( -(aNewStartPos.X() - mpImpl->maStartDocPos.X()), -(aNewStartPos.Y() - mpImpl->maStartDocPos.Y()) ); - } - - if ( aEditCursor.Right() < aEditCursor.Left() ) - { - long n = aEditCursor.Left(); - aEditCursor.Left() = aEditCursor.Right(); - aEditCursor.Right() = n; - } - - Point aPoint( GetWindowPos( !mpImpl->mpTextEngine->IsRightToLeft() ? aEditCursor.TopLeft() : aEditCursor.TopRight() ) ); - mpImpl->mpCursor->SetPos( aPoint ); - mpImpl->mpCursor->SetSize( aEditCursor.GetSize() ); - if ( bForceVisCursor && mpImpl->mbCursorEnabled ) - mpImpl->mpCursor->Show(); -} - -sal_Bool TextView::SetCursorAtPoint( const Point& rPosPixel ) -{ - mpImpl->mpTextEngine->CheckIdleFormatter(); - - Point aDocPos = GetDocPos( rPosPixel ); - - TextPaM aPaM = mpImpl->mpTextEngine->GetPaM( aDocPos ); - - // aTmpNewSel: Diff zwischen alt und neu, nicht die neue Selektion - TextSelection aTmpNewSel( mpImpl->maSelection.GetEnd(), aPaM ); - TextSelection aNewSel( mpImpl->maSelection ); - aNewSel.GetEnd() = aPaM; - - if ( !mpImpl->mpSelEngine->HasAnchor() ) - { - if ( mpImpl->maSelection.GetStart() != aPaM ) - mpImpl->mpTextEngine->CursorMoved( mpImpl->maSelection.GetStart().GetPara() ); - aNewSel.GetStart() = aPaM; - ImpSetSelection( aNewSel ); - } - else - { - ImpSetSelection( aNewSel ); - ShowSelection( aTmpNewSel ); - } - - sal_Bool bForceCursor = mpImpl->mpDDInfo ? sal_False : sal_True; // && !mbInSelection - ImpShowCursor( mpImpl->mbAutoScroll, bForceCursor, sal_False ); - return sal_True; -} - -sal_Bool TextView::IsSelectionAtPoint( const Point& rPosPixel ) -{ -// if ( !Rectangle( Point(), mpImpl->mpWindow->GetOutputSizePixel() ).IsInside( rPosPixel ) && !mbInSelection ) -// return sal_False; - - Point aDocPos = GetDocPos( rPosPixel ); - TextPaM aPaM = mpImpl->mpTextEngine->GetPaM( aDocPos, sal_False ); - // Bei Hyperlinks D&D auch ohne Selektion starten. - // BeginDrag wird aber nur gerufen, wenn IsSelectionAtPoint() - // Problem: IsSelectionAtPoint wird bei Command() nicht gerufen, - // wenn vorher im MBDown schon sal_False returnt wurde. - return ( IsInSelection( aPaM ) || - ( /* mpImpl->mpSelEngine->IsInCommand() && */ mpImpl->mpTextEngine->FindAttrib( aPaM, TEXTATTR_HYPERLINK ) ) ); -} - -sal_Bool TextView::IsInSelection( const TextPaM& rPaM ) -{ - TextSelection aSel = mpImpl->maSelection; - aSel.Justify(); - - sal_uLong nStartNode = aSel.GetStart().GetPara(); - sal_uLong nEndNode = aSel.GetEnd().GetPara(); - sal_uLong nCurNode = rPaM.GetPara(); - - if ( ( nCurNode > nStartNode ) && ( nCurNode < nEndNode ) ) - return sal_True; - - if ( nStartNode == nEndNode ) - { - if ( nCurNode == nStartNode ) - if ( ( rPaM.GetIndex() >= aSel.GetStart().GetIndex() ) && ( rPaM.GetIndex() < aSel.GetEnd().GetIndex() ) ) - return sal_True; - } - else if ( ( nCurNode == nStartNode ) && ( rPaM.GetIndex() >= aSel.GetStart().GetIndex() ) ) - return sal_True; - else if ( ( nCurNode == nEndNode ) && ( rPaM.GetIndex() < aSel.GetEnd().GetIndex() ) ) - return sal_True; - - return sal_False; -} - -void TextView::ImpHideDDCursor() -{ - if ( mpImpl->mpDDInfo && mpImpl->mpDDInfo->mbVisCursor ) - { - mpImpl->mpDDInfo->maCursor.Hide(); - mpImpl->mpDDInfo->mbVisCursor = sal_False; - } -} - -void TextView::ImpShowDDCursor() -{ - if ( !mpImpl->mpDDInfo->mbVisCursor ) - { - Rectangle aCursor = mpImpl->mpTextEngine->PaMtoEditCursor( mpImpl->mpDDInfo->maDropPos, sal_True ); - aCursor.Right()++; - aCursor.SetPos( GetWindowPos( aCursor.TopLeft() ) ); - - mpImpl->mpDDInfo->maCursor.SetWindow( mpImpl->mpWindow ); - mpImpl->mpDDInfo->maCursor.SetPos( aCursor.TopLeft() ); - mpImpl->mpDDInfo->maCursor.SetSize( aCursor.GetSize() ); - mpImpl->mpDDInfo->maCursor.Show(); - mpImpl->mpDDInfo->mbVisCursor = sal_True; - } -} - -void TextView::SetPaintSelection( sal_Bool bPaint ) -{ - if ( bPaint != mpImpl->mbPaintSelection ) - { - mpImpl->mbPaintSelection = bPaint; - ShowSelection( mpImpl->maSelection ); - } -} - -sal_Bool TextView::Read( SvStream& rInput ) -{ - sal_Bool bDone = mpImpl->mpTextEngine->Read( rInput, &mpImpl->maSelection ); - ShowCursor(); - return bDone; -} - -bool TextView::ImplTruncateNewText( rtl::OUString& rNewText ) const -{ - bool bTruncated = false; - - if( rNewText.getLength() > 65534 ) // limit to String API - { - rNewText = rNewText.copy( 0, 65534 ); - bTruncated = true; - } - - sal_uLong nMaxLen = mpImpl->mpTextEngine->GetMaxTextLen(); - // 0 means unlimited, there is just the String API limit handled above - if( nMaxLen != 0 ) - { - sal_uLong nCurLen = mpImpl->mpTextEngine->GetTextLen(); - - sal_uInt32 nNewLen = rNewText.getLength(); - if ( nCurLen + nNewLen > nMaxLen ) - { - // see how much text will be replaced - sal_uLong nSelLen = mpImpl->mpTextEngine->GetTextLen( mpImpl->maSelection ); - if ( nCurLen + nNewLen - nSelLen > nMaxLen ) - { - sal_uInt32 nTruncatedLen = static_cast(nMaxLen - (nCurLen - nSelLen)); - rNewText = rNewText.copy( 0, nTruncatedLen ); - bTruncated = true; - } - } - } - return bTruncated; -} - -sal_Bool TextView::ImplCheckTextLen( const String& rNewText ) -{ - sal_Bool bOK = sal_True; - if ( mpImpl->mpTextEngine->GetMaxTextLen() ) - { - sal_uLong n = mpImpl->mpTextEngine->GetTextLen(); - n += rNewText.Len(); - if ( n > mpImpl->mpTextEngine->GetMaxTextLen() ) - { - // nur dann noch ermitteln, wie viel Text geloescht wird - n -= mpImpl->mpTextEngine->GetTextLen( mpImpl->maSelection ); - if ( n > mpImpl->mpTextEngine->GetMaxTextLen() ) - bOK = sal_False; - } - } - return bOK; -} - -void TextView::dragGestureRecognized( const ::com::sun::star::datatransfer::dnd::DragGestureEvent& rDGE ) throw (::com::sun::star::uno::RuntimeException) -{ - if ( mpImpl->mbClickedInSelection ) - { - SolarMutexGuard aVclGuard; - - DBG_ASSERT( mpImpl->maSelection.HasRange(), "TextView::dragGestureRecognized: mpImpl->mbClickedInSelection, but no selection?" ); - - delete mpImpl->mpDDInfo; - mpImpl->mpDDInfo = new TextDDInfo; - mpImpl->mpDDInfo->mbStarterOfDD = sal_True; - - TETextDataObject* pDataObj = new TETextDataObject( GetSelected() ); - - if ( mpImpl->mpTextEngine->HasAttrib( TEXTATTR_HYPERLINK ) ) // Dann auch als HTML - mpImpl->mpTextEngine->Write( pDataObj->GetHTMLStream(), &mpImpl->maSelection, sal_True ); - - - /* - // D&D eines Hyperlinks. - // Besser waere es im MBDown sich den MBDownPaM zu merken, - // ist dann aber inkompatibel => spaeter mal umstellen. - TextPaM aPaM( mpImpl->mpTextEngine->GetPaM( GetDocPos( GetWindow()->GetPointerPosPixel() ) ) ); - const TextCharAttrib* pAttr = mpImpl->mpTextEngine->FindCharAttrib( aPaM, TEXTATTR_HYPERLINK ); - if ( pAttr ) - { - aSel = aPaM; - aSel.GetStart().GetIndex() = pAttr->GetStart(); - aSel.GetEnd().GetIndex() = pAttr->GetEnd(); - - const TextAttribHyperLink& rLink = (const TextAttribHyperLink&)pAttr->GetAttr(); - String aText( rLink.GetDescription() ); - if ( !aText.Len() ) - aText = mpImpl->mpTextEngine->GetText( aSel ); - INetBookmark aBookmark( rLink.GetURL(), aText ); - aBookmark.CopyDragServer(); - } - */ - - mpImpl->mpCursor->Hide(); - - sal_Int8 nActions = datatransfer::dnd::DNDConstants::ACTION_COPY; - if ( !IsReadOnly() ) - nActions |= datatransfer::dnd::DNDConstants::ACTION_MOVE; - rDGE.DragSource->startDrag( rDGE, nActions, 0 /*cursor*/, 0 /*image*/, pDataObj, mpImpl->mxDnDListener ); - } -} - -void TextView::dragDropEnd( const ::com::sun::star::datatransfer::dnd::DragSourceDropEvent& ) throw (::com::sun::star::uno::RuntimeException) -{ - ImpHideDDCursor(); - delete mpImpl->mpDDInfo; - mpImpl->mpDDInfo = NULL; -} - -void TextView::drop( const ::com::sun::star::datatransfer::dnd::DropTargetDropEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException) -{ - SolarMutexGuard aVclGuard; - - sal_Bool bChanges = sal_False; - if ( !mpImpl->mbReadOnly && mpImpl->mpDDInfo ) - { - ImpHideDDCursor(); - - // Daten fuer das loeschen nach einem DROP_MOVE: - TextSelection aPrevSel( mpImpl->maSelection ); - aPrevSel.Justify(); - sal_uLong nPrevParaCount = mpImpl->mpTextEngine->GetParagraphCount(); - sal_uInt16 nPrevStartParaLen = mpImpl->mpTextEngine->GetTextLen( aPrevSel.GetStart().GetPara() ); - - sal_Bool bStarterOfDD = sal_False; - for ( sal_uInt16 nView = mpImpl->mpTextEngine->GetViewCount(); nView && !bStarterOfDD; ) - bStarterOfDD = mpImpl->mpTextEngine->GetView( --nView )->mpImpl->mpDDInfo ? mpImpl->mpTextEngine->GetView( nView )->mpImpl->mpDDInfo->mbStarterOfDD : sal_False; - - HideSelection(); - ImpSetSelection( mpImpl->mpDDInfo->maDropPos ); - - mpImpl->mpTextEngine->UndoActionStart(); - - String aText; - uno::Reference< datatransfer::XTransferable > xDataObj = rDTDE.Transferable; - if ( xDataObj.is() ) - { - datatransfer::DataFlavor aFlavor; - SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor ); - if ( xDataObj->isDataFlavorSupported( aFlavor ) ) - { - uno::Any aData = xDataObj->getTransferData( aFlavor ); - ::rtl::OUString aOUString; - aData >>= aOUString; - aText = convertLineEnd(aOUString, LINEEND_LF); - } - } - - if ( aText.Len() && ( aText.GetChar( aText.Len()-1 ) == LINE_SEP ) ) - aText.Erase( aText.Len()-1 ); - - TextPaM aTempStart = mpImpl->maSelection.GetStart(); - if ( ImplCheckTextLen( aText ) ) - ImpSetSelection( mpImpl->mpTextEngine->ImpInsertText( mpImpl->mpDDInfo->maDropPos, aText ) ); - if(mpImpl->mbSupportProtectAttribute) - { - mpImpl->mpTextEngine->SetAttrib( TextAttribProtect(), - aTempStart.GetPara(), - aTempStart.GetIndex(), - mpImpl->maSelection.GetEnd().GetIndex(), sal_False ); - } - - if ( aPrevSel.HasRange() && - !mpImpl->mbSupportProtectAttribute && // don't remove currently selected element - (( rDTDE.DropAction & datatransfer::dnd::DNDConstants::ACTION_MOVE ) || !bStarterOfDD) ) - { - // ggf. Selection anpasssen: - if ( ( mpImpl->mpDDInfo->maDropPos.GetPara() < aPrevSel.GetStart().GetPara() ) || - ( ( mpImpl->mpDDInfo->maDropPos.GetPara() == aPrevSel.GetStart().GetPara() ) - && ( mpImpl->mpDDInfo->maDropPos.GetIndex() < aPrevSel.GetStart().GetIndex() ) ) ) - { - sal_uLong nNewParasBeforeSelection = - mpImpl->mpTextEngine->GetParagraphCount() - nPrevParaCount; - - aPrevSel.GetStart().GetPara() += nNewParasBeforeSelection; - aPrevSel.GetEnd().GetPara() += nNewParasBeforeSelection; - - if ( mpImpl->mpDDInfo->maDropPos.GetPara() == aPrevSel.GetStart().GetPara() ) - { - sal_uInt16 nNewChars = - mpImpl->mpTextEngine->GetTextLen( aPrevSel.GetStart().GetPara() ) - nPrevStartParaLen; - - aPrevSel.GetStart().GetIndex() = - aPrevSel.GetStart().GetIndex() + nNewChars; - if ( aPrevSel.GetStart().GetPara() == aPrevSel.GetEnd().GetPara() ) - aPrevSel.GetEnd().GetIndex() = - aPrevSel.GetEnd().GetIndex() + nNewChars; - } - } - else - { - // aktuelle Selektion anpassen - TextPaM aPaM = mpImpl->maSelection.GetStart(); - aPaM.GetPara() -= ( aPrevSel.GetEnd().GetPara() - aPrevSel.GetStart().GetPara() ); - if ( aPrevSel.GetEnd().GetPara() == mpImpl->mpDDInfo->maDropPos.GetPara() ) - { - aPaM.GetIndex() = - aPaM.GetIndex() - aPrevSel.GetEnd().GetIndex(); - if ( aPrevSel.GetStart().GetPara() == mpImpl->mpDDInfo->maDropPos.GetPara() ) - aPaM.GetIndex() = - aPaM.GetIndex() + aPrevSel.GetStart().GetIndex(); - } - ImpSetSelection( aPaM ); - - } - mpImpl->mpTextEngine->ImpDeleteText( aPrevSel ); - } - - mpImpl->mpTextEngine->UndoActionEnd(); - - delete mpImpl->mpDDInfo; - mpImpl->mpDDInfo = 0; - - mpImpl->mpTextEngine->FormatAndUpdate( this ); - - mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) ); - } - rDTDE.Context->dropComplete( bChanges ); -} - -void TextView::dragEnter( const ::com::sun::star::datatransfer::dnd::DropTargetDragEnterEvent& ) throw (::com::sun::star::uno::RuntimeException) -{ -} - -void TextView::dragExit( const ::com::sun::star::datatransfer::dnd::DropTargetEvent& ) throw (::com::sun::star::uno::RuntimeException) -{ - SolarMutexGuard aVclGuard; - ImpHideDDCursor(); -} - -void TextView::dragOver( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException) -{ - SolarMutexGuard aVclGuard; - - if ( !mpImpl->mpDDInfo ) - mpImpl->mpDDInfo = new TextDDInfo; - - TextPaM aPrevDropPos = mpImpl->mpDDInfo->maDropPos; - Point aMousePos( rDTDE.LocationX, rDTDE.LocationY ); - Point aDocPos = GetDocPos( aMousePos ); - mpImpl->mpDDInfo->maDropPos = mpImpl->mpTextEngine->GetPaM( aDocPos ); - - sal_Bool bProtected = sal_False; - if(mpImpl->mbSupportProtectAttribute) - { - const TextCharAttrib* pStartAttr = mpImpl->mpTextEngine->FindCharAttrib( - mpImpl->mpDDInfo->maDropPos, - TEXTATTR_PROTECTED ); - bProtected = pStartAttr != 0 && - pStartAttr->GetStart() != mpImpl->mpDDInfo->maDropPos.GetIndex() && - pStartAttr->GetEnd() != mpImpl->mpDDInfo->maDropPos.GetIndex(); - } - // Don't drop in selection or in read only engine - if ( IsReadOnly() || IsInSelection( mpImpl->mpDDInfo->maDropPos ) || bProtected) - { - ImpHideDDCursor(); - rDTDE.Context->rejectDrag(); - } - else - { - // Alten Cursor wegzeichnen... - if ( !mpImpl->mpDDInfo->mbVisCursor || ( aPrevDropPos != mpImpl->mpDDInfo->maDropPos ) ) - { - ImpHideDDCursor(); - ImpShowDDCursor(); - } - rDTDE.Context->acceptDrag( rDTDE.DropAction ); - } -} - -Point TextView::ImpGetOutputStartPos( const Point& rStartDocPos ) const -{ - Point aStartPos( -rStartDocPos.X(), -rStartDocPos.Y() ); - if ( mpImpl->mpTextEngine->IsRightToLeft() ) - { - Size aSz = mpImpl->mpWindow->GetOutputSizePixel(); - aStartPos.X() = rStartDocPos.X() + aSz.Width() - 1; // -1: Start is 0 - } - return aStartPos; -} - -Point TextView::GetDocPos( const Point& rWindowPos ) const -{ - // Fensterposition => Dokumentposition - - Point aPoint; - - aPoint.Y() = rWindowPos.Y() + mpImpl->maStartDocPos.Y(); - - if ( !mpImpl->mpTextEngine->IsRightToLeft() ) - { - aPoint.X() = rWindowPos.X() + mpImpl->maStartDocPos.X(); - } - else - { - Size aSz = mpImpl->mpWindow->GetOutputSizePixel(); - aPoint.X() = ( aSz.Width() - 1 ) - rWindowPos.X() + mpImpl->maStartDocPos.X(); - } - - return aPoint; -} - -Point TextView::GetWindowPos( const Point& rDocPos ) const -{ - // Dokumentposition => Fensterposition - - Point aPoint; - - aPoint.Y() = rDocPos.Y() - mpImpl->maStartDocPos.Y(); - - if ( !mpImpl->mpTextEngine->IsRightToLeft() ) - { - aPoint.X() = rDocPos.X() - mpImpl->maStartDocPos.X(); - } - else - { - Size aSz = mpImpl->mpWindow->GetOutputSizePixel(); - aPoint.X() = ( aSz.Width() - 1 ) - ( rDocPos.X() - mpImpl->maStartDocPos.X() ); - } - - return aPoint; -} - -sal_Int32 TextView::GetLineNumberOfCursorInSelection() const -{ - // PROGRESS - sal_Int32 nLineNo = -1; - if( mpImpl->mbCursorEnabled ) - { - TextPaM aPaM = GetSelection().GetEnd(); - TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() ); - nLineNo = pPPortion->GetLineNumber( aPaM.GetIndex(), sal_False ); - if( mpImpl->mbCursorAtEndOfLine ) - --nLineNo; - } - return nLineNo; -} - - -// ------------------------------------------------------------------------- -// (+) class TextSelFunctionSet -// ------------------------------------------------------------------------- -TextSelFunctionSet::TextSelFunctionSet( TextView* pView ) -{ - mpView = pView; -} - -void TextSelFunctionSet::BeginDrag() -{ -} - -void TextSelFunctionSet::CreateAnchor() -{ -// TextSelection aSel( mpView->GetSelection() ); -// aSel.GetStart() = aSel.GetEnd(); -// mpView->SetSelection( aSel ); - - // Es darf kein ShowCursor folgen: - mpView->HideSelection(); - mpView->ImpSetSelection( mpView->mpImpl->maSelection.GetEnd() ); -} - -sal_Bool TextSelFunctionSet::SetCursorAtPoint( const Point& rPointPixel, sal_Bool ) -{ - return mpView->SetCursorAtPoint( rPointPixel ); -} - -sal_Bool TextSelFunctionSet::IsSelectionAtPoint( const Point& rPointPixel ) -{ - return mpView->IsSelectionAtPoint( rPointPixel ); -} - -void TextSelFunctionSet::DeselectAll() -{ - CreateAnchor(); -} - -void TextSelFunctionSet::DeselectAtPoint( const Point& ) -{ - // Nur bei Mehrfachselektion -} - -void TextSelFunctionSet::DestroyAnchor() -{ - // Nur bei Mehrfachselektion -} -TextEngine* TextView::GetTextEngine() const -{ return mpImpl->mpTextEngine; } -Window* TextView::GetWindow() const -{ return mpImpl->mpWindow; } -void TextView::EnableCursor( sal_Bool bEnable ) -{ mpImpl->mbCursorEnabled = bEnable; } -sal_Bool TextView::IsCursorEnabled() const -{ return mpImpl->mbCursorEnabled; } -void TextView::SetStartDocPos( const Point& rPos ) -{ mpImpl->maStartDocPos = rPos; } -const Point& TextView::GetStartDocPos() const -{ return mpImpl->maStartDocPos; } -void TextView::SetAutoIndentMode( sal_Bool bAutoIndent ) -{ mpImpl->mbAutoIndent = bAutoIndent; } -sal_Bool TextView::IsReadOnly() const -{ return mpImpl->mbReadOnly; } -void TextView::SetAutoScroll( sal_Bool bAutoScroll ) -{ mpImpl->mbAutoScroll = bAutoScroll; } -sal_Bool TextView::IsAutoScroll() const -{ return mpImpl->mbAutoScroll; } -sal_Bool TextView::HasSelection() const -{ return mpImpl->maSelection.HasRange(); } -sal_Bool TextView::IsInsertMode() const -{ return mpImpl->mbInsertMode; } -void TextView::SupportProtectAttribute(sal_Bool bSupport) -{ mpImpl->mbSupportProtectAttribute = bSupport;} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svtools/source/edit/textwindowpeer.cxx b/svtools/source/edit/textwindowpeer.cxx index 3609063..59eee86 100644 --- a/svtools/source/edit/textwindowpeer.cxx +++ b/svtools/source/edit/textwindowpeer.cxx @@ -19,7 +19,7 @@ #include -#include +#include #include "svtaccessiblefactory.hxx" namespace css = ::com::sun::star; diff --git a/svtools/source/edit/txtattr.cxx b/svtools/source/edit/txtattr.cxx deleted file mode 100644 index a332482..0000000 --- a/svtools/source/edit/txtattr.cxx +++ /dev/null @@ -1,164 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2000, 2010 Oracle and/or its affiliates. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * - * for a copy of the LGPLv3 License. - * - ************************************************************************/ - - -#include -#include - - - - -TextAttrib::~TextAttrib() -{ -} - -int TextAttrib::operator==( const TextAttrib& rAttr ) const -{ - return mnWhich == rAttr.mnWhich; -} - - -TextAttribFontColor::TextAttribFontColor( const Color& rColor ) - : TextAttrib( TEXTATTR_FONTCOLOR ), maColor( rColor ) -{ -} - -TextAttribFontColor::TextAttribFontColor( const TextAttribFontColor& rAttr ) - : TextAttrib( rAttr ), maColor( rAttr.maColor ) -{ -} - -TextAttribFontColor::~TextAttribFontColor() -{ -} - -void TextAttribFontColor::SetFont( Font& rFont ) const -{ - rFont.SetColor( maColor ); -} - -TextAttrib* TextAttribFontColor::Clone() const -{ - return new TextAttribFontColor( *this ); -} - -int TextAttribFontColor::operator==( const TextAttrib& rAttr ) const -{ - return ( ( TextAttrib::operator==(rAttr ) ) && - ( maColor == ((const TextAttribFontColor&)rAttr).maColor ) ); -} - -TextAttribFontWeight::TextAttribFontWeight( FontWeight eWeight ) - : TextAttrib( TEXTATTR_FONTWEIGHT ), meWeight( eWeight ) -{ -} - -TextAttribFontWeight::TextAttribFontWeight( const TextAttribFontWeight& rAttr ) - : TextAttrib( rAttr ), meWeight( rAttr.meWeight ) -{ -} - -TextAttribFontWeight::~TextAttribFontWeight() -{ -} - -void TextAttribFontWeight::SetFont( Font& rFont ) const -{ - rFont.SetWeight( meWeight ); -} - -TextAttrib* TextAttribFontWeight::Clone() const -{ - return new TextAttribFontWeight( *this ); -} - -int TextAttribFontWeight::operator==( const TextAttrib& rAttr ) const -{ - return ( ( TextAttrib::operator==(rAttr ) ) && - ( meWeight == ((const TextAttribFontWeight&)rAttr).meWeight ) ); -} - - -TextAttribHyperLink::TextAttribHyperLink( const TextAttribHyperLink& rAttr ) - : TextAttrib( rAttr ), maURL( rAttr.maURL ), maDescription( rAttr.maDescription ) -{ - maColor = rAttr.maColor; -} - -TextAttribHyperLink::~TextAttribHyperLink() -{ -} - -void TextAttribHyperLink::SetFont( Font& rFont ) const -{ - rFont.SetColor( maColor ); - rFont.SetUnderline( UNDERLINE_SINGLE ); -} - -TextAttrib* TextAttribHyperLink::Clone() const -{ - return new TextAttribHyperLink( *this ); -} - -int TextAttribHyperLink::operator==( const TextAttrib& rAttr ) const -{ - return ( ( TextAttrib::operator==(rAttr ) ) && - ( maURL == ((const TextAttribHyperLink&)rAttr).maURL ) && - ( maDescription == ((const TextAttribHyperLink&)rAttr).maDescription ) && - ( maColor == ((const TextAttribHyperLink&)rAttr).maColor ) ); -} - -TextAttribProtect::TextAttribProtect() : - TextAttrib( TEXTATTR_PROTECTED ) -{ -} - -TextAttribProtect::TextAttribProtect( const TextAttribProtect&) : - TextAttrib( TEXTATTR_PROTECTED ) -{ -} - -TextAttribProtect::~TextAttribProtect() -{ -} - -void TextAttribProtect::SetFont( Font& ) const -{ -} - -TextAttrib* TextAttribProtect::Clone() const -{ - return new TextAttribProtect(); -} - -int TextAttribProtect::operator==( const TextAttrib& rAttr ) const -{ - return ( TextAttrib::operator==(rAttr ) ); -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svtools/source/edit/xtextedt.cxx b/svtools/source/edit/xtextedt.cxx deleted file mode 100644 index a02f6aa..0000000 --- a/svtools/source/edit/xtextedt.cxx +++ /dev/null @@ -1,421 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2000, 2010 Oracle and/or its affiliates. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * - * for a copy of the LGPLv3 License. - * - ************************************************************************/ - - -#include -#include // International -#include -#include -#include - -using namespace ::com::sun::star; - - - -// ------------------------------------------------------------------------- -// class ExtTextEngine -// ------------------------------------------------------------------------- -ExtTextEngine::ExtTextEngine() : maGroupChars(rtl::OUString("(){}[]")) -{ -} - -ExtTextEngine::~ExtTextEngine() -{ -} - -TextSelection ExtTextEngine::MatchGroup( const TextPaM& rCursor ) const -{ - TextSelection aSel( rCursor ); - sal_uInt16 nPos = rCursor.GetIndex(); - sal_uLong nPara = rCursor.GetPara(); - sal_uLong nParas = GetParagraphCount(); - if ( ( nPara < nParas ) && ( nPos < GetTextLen( nPara ) ) ) - { - sal_uInt16 nMatchChar = maGroupChars.Search( GetText( rCursor.GetPara() ).GetChar( nPos ) ); - if ( nMatchChar != STRING_NOTFOUND ) - { - if ( ( nMatchChar % 2 ) == 0 ) - { - // Vorwaerts suchen... - sal_Unicode nSC = maGroupChars.GetChar( nMatchChar ); - sal_Unicode nEC = maGroupChars.GetChar( nMatchChar+1 ); - - sal_uInt16 nCur = nPos+1; - sal_uInt16 nLevel = 1; - while ( nLevel && ( nPara < nParas ) ) - { - XubString aStr = GetText( nPara ); - while ( nCur < aStr.Len() ) - { - if ( aStr.GetChar( nCur ) == nSC ) - nLevel++; - else if ( aStr.GetChar( nCur ) == nEC ) - { - nLevel--; - if ( !nLevel ) - break; // while nCur... - } - nCur++; - } - - if ( nLevel ) - { - nPara++; - nCur = 0; - } - } - if ( nLevel == 0 ) // gefunden - { - aSel.GetStart() = rCursor; - aSel.GetEnd() = TextPaM( nPara, nCur+1 ); - } - } - else - { - // Rueckwaerts suchen... - xub_Unicode nEC = maGroupChars.GetChar( nMatchChar ); - xub_Unicode nSC = maGroupChars.GetChar( nMatchChar-1 ); - - sal_uInt16 nCur = rCursor.GetIndex()-1; - sal_uInt16 nLevel = 1; - while ( nLevel ) - { - if ( GetTextLen( nPara ) ) - { - XubString aStr = GetText( nPara ); - while ( nCur ) - { - if ( aStr.GetChar( nCur ) == nSC ) - { - nLevel--; - if ( !nLevel ) - break; // while nCur... - } - else if ( aStr.GetChar( nCur ) == nEC ) - nLevel++; - - nCur--; - } - } - - if ( nLevel ) - { - if ( nPara ) - { - nPara--; - nCur = GetTextLen( nPara )-1; // egal ob negativ, weil if Len() - } - else - break; - } - } - - if ( nLevel == 0 ) // gefunden - { - aSel.GetStart() = rCursor; - aSel.GetStart().GetIndex()++; // hinter das Zeichen - aSel.GetEnd() = TextPaM( nPara, nCur ); - } - } - } - } - return aSel; -} - -sal_Bool ExtTextEngine::Search( TextSelection& rSel, const util::SearchOptions& rSearchOptions, sal_Bool bForward ) -{ - TextSelection aSel( rSel ); - aSel.Justify(); - - sal_Bool bSearchInSelection = (0 != (rSearchOptions.searchFlag & util::SearchFlags::REG_NOT_BEGINOFLINE) ); - - TextPaM aStartPaM( aSel.GetEnd() ); - if ( aSel.HasRange() && ( ( bSearchInSelection && bForward ) || ( !bSearchInSelection && !bForward ) ) ) - { - aStartPaM = aSel.GetStart(); - } - - bool bFound = false; - sal_uLong nStartNode, nEndNode; - - if ( bSearchInSelection ) - nEndNode = bForward ? aSel.GetEnd().GetPara() : aSel.GetStart().GetPara(); - else - nEndNode = bForward ? (GetParagraphCount()-1) : 0; - - nStartNode = aStartPaM.GetPara(); - - util::SearchOptions aOptions( rSearchOptions ); - aOptions.Locale = Application::GetSettings().GetLocale(); - utl::TextSearch aSearcher( rSearchOptions ); - - // ueber die Absaetze iterieren... - for ( sal_uLong nNode = nStartNode; - bForward ? ( nNode <= nEndNode) : ( nNode >= nEndNode ); - bForward ? nNode++ : nNode-- ) - { - String aText = GetText( nNode ); - sal_uInt16 nStartPos = 0; - sal_uInt16 nEndPos = aText.Len(); - if ( nNode == nStartNode ) - { - if ( bForward ) - nStartPos = aStartPaM.GetIndex(); - else - nEndPos = aStartPaM.GetIndex(); - } - if ( ( nNode == nEndNode ) && bSearchInSelection ) - { - if ( bForward ) - nEndPos = aSel.GetEnd().GetIndex(); - else - nStartPos = aSel.GetStart().GetIndex(); - } - - if ( bForward ) - bFound = aSearcher.SearchFrwrd( aText, &nStartPos, &nEndPos ); - else - bFound = aSearcher.SearchBkwrd( aText, &nEndPos, &nStartPos ); - - if ( bFound ) - { - rSel.GetStart().GetPara() = nNode; - rSel.GetStart().GetIndex() = nStartPos; - rSel.GetEnd().GetPara() = nNode; - rSel.GetEnd().GetIndex() = nEndPos; - // Ueber den Absatz selektieren? - // Select over the paragraph? - // FIXME This should be max long... - if( nEndPos == sal::static_int_cast(-1) ) // sal_uInt16 for 0 and -1 ! - { - if ( (rSel.GetEnd().GetPara()+1) < GetParagraphCount() ) - { - rSel.GetEnd().GetPara()++; - rSel.GetEnd().GetIndex() = 0; - } - else - { - rSel.GetEnd().GetIndex() = nStartPos; - bFound = false; - } - } - - break; - } - - if ( !bForward && !nNode ) // Bei rueckwaertsuche, wenn nEndNode = 0: - break; - } - - return bFound; -} - - -// ------------------------------------------------------------------------- -// class ExtTextView -// ------------------------------------------------------------------------- -ExtTextView::ExtTextView( ExtTextEngine* pEng, Window* pWindow ) - : TextView( pEng, pWindow ) -{ -} - -ExtTextView::~ExtTextView() -{ -} - -sal_Bool ExtTextView::MatchGroup() -{ - TextSelection aTmpSel( GetSelection() ); - aTmpSel.Justify(); - if ( ( aTmpSel.GetStart().GetPara() != aTmpSel.GetEnd().GetPara() ) || - ( ( aTmpSel.GetEnd().GetIndex() - aTmpSel.GetStart().GetIndex() ) > 1 ) ) - { - return sal_False; - } - - TextSelection aMatchSel = ((ExtTextEngine*)GetTextEngine())->MatchGroup( aTmpSel.GetStart() ); - if ( aMatchSel.HasRange() ) - SetSelection( aMatchSel ); - - return aMatchSel.HasRange() ? sal_True : sal_False; -} - -sal_Bool ExtTextView::Search( const util::SearchOptions& rSearchOptions, sal_Bool bForward ) -{ - sal_Bool bFound = sal_False; - TextSelection aSel( GetSelection() ); - if ( ((ExtTextEngine*)GetTextEngine())->Search( aSel, rSearchOptions, bForward ) ) - { - bFound = sal_True; - // Erstmal den Anfang des Wortes als Selektion einstellen, - // damit das ganze Wort in den sichtbaren Bereich kommt. - SetSelection( aSel.GetStart() ); - ShowCursor( sal_True, sal_False ); - } - else - { - aSel = GetSelection().GetEnd(); - } - - SetSelection( aSel ); - ShowCursor(); - - return bFound; -} - -sal_uInt16 ExtTextView::Replace( const util::SearchOptions& rSearchOptions, sal_Bool bAll, sal_Bool bForward ) -{ - sal_uInt16 nFound = 0; - - if ( !bAll ) - { - if ( GetSelection().HasRange() ) - { - InsertText( rSearchOptions.replaceString ); - nFound = 1; - Search( rSearchOptions, bForward ); // gleich zum naechsten - } - else - { - if( Search( rSearchOptions, bForward ) ) - nFound = 1; - } - } - else - { - // Der Writer ersetzt alle, vom Anfang bis Ende... - - ExtTextEngine* pTextEngine = (ExtTextEngine*)GetTextEngine(); - - // HideSelection(); - TextSelection aSel; - - sal_Bool bSearchInSelection = (0 != (rSearchOptions.searchFlag & util::SearchFlags::REG_NOT_BEGINOFLINE) ); - if ( bSearchInSelection ) - { - aSel = GetSelection(); - aSel.Justify(); - } - - TextSelection aSearchSel( aSel ); - - sal_Bool bFound = pTextEngine->Search( aSel, rSearchOptions, sal_True ); - if ( bFound ) - pTextEngine->UndoActionStart(); - while ( bFound ) - { - nFound++; - - TextPaM aNewStart = pTextEngine->ImpInsertText( aSel, rSearchOptions.replaceString ); - aSel = aSearchSel; - aSel.GetStart() = aNewStart; - bFound = pTextEngine->Search( aSel, rSearchOptions, sal_True ); - } - if ( nFound ) - { - SetSelection( aSel.GetStart() ); - pTextEngine->FormatAndUpdate( this ); - pTextEngine->UndoActionEnd(); - } - } - return nFound; -} - -sal_Bool ExtTextView::ImpIndentBlock( sal_Bool bRight ) -{ - sal_Bool bDone = sal_False; - - TextSelection aSel = GetSelection(); - aSel.Justify(); - - HideSelection(); - GetTextEngine()->UndoActionStart(); - - sal_uLong nStartPara = aSel.GetStart().GetPara(); - sal_uLong nEndPara = aSel.GetEnd().GetPara(); - if ( aSel.HasRange() && !aSel.GetEnd().GetIndex() ) - { - nEndPara--; // den dann nicht einruecken... - } - - for ( sal_uLong nPara = nStartPara; nPara <= nEndPara; nPara++ ) - { - if ( bRight ) - { - // Tabs hinzufuegen - GetTextEngine()->ImpInsertText( TextPaM( nPara, 0 ), '\t' ); - bDone = sal_True; - } - else - { - // Tabs/Blanks entfernen - String aText = GetTextEngine()->GetText( nPara ); - if ( aText.Len() && ( - ( aText.GetChar( 0 ) == '\t' ) || - ( aText.GetChar( 0 ) == ' ' ) ) ) - { - GetTextEngine()->ImpDeleteText( TextSelection( TextPaM( nPara, 0 ), TextPaM( nPara, 1 ) ) ); - bDone = sal_True; - } - } - } - - GetTextEngine()->UndoActionEnd(); - - sal_Bool bRange = aSel.HasRange(); - if ( bRight ) - { - aSel.GetStart().GetIndex()++; - if ( bRange && ( aSel.GetEnd().GetPara() == nEndPara ) ) - aSel.GetEnd().GetIndex()++; - } - else - { - if ( aSel.GetStart().GetIndex() ) - aSel.GetStart().GetIndex()--; - if ( bRange && aSel.GetEnd().GetIndex() ) - aSel.GetEnd().GetIndex()--; - } - - ImpSetSelection( aSel ); - GetTextEngine()->FormatAndUpdate( this ); - - return bDone; -} - -sal_Bool ExtTextView::IndentBlock() -{ - return ImpIndentBlock( sal_True ); -} - -sal_Bool ExtTextView::UnindentBlock() -{ - return ImpIndentBlock( sal_False ); -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/dialog/docrecovery.cxx b/svx/source/dialog/docrecovery.cxx index 32685fa..f5fdf8d 100644 --- a/svx/source/dialog/docrecovery.cxx +++ b/svx/source/dialog/docrecovery.cxx @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/sw/source/ui/dbui/mmaddressblockpage.cxx b/sw/source/ui/dbui/mmaddressblockpage.cxx index 5cde4aa..a9c86b2 100644 --- a/sw/source/ui/dbui/mmaddressblockpage.cxx +++ b/sw/source/ui/dbui/mmaddressblockpage.cxx @@ -33,8 +33,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include diff --git a/sw/source/ui/docvw/srcedtw.cxx b/sw/source/ui/docvw/srcedtw.cxx index c6bb14f..66273f9 100644 --- a/sw/source/ui/docvw/srcedtw.cxx +++ b/sw/source/ui/docvw/srcedtw.cxx @@ -38,13 +38,13 @@ #include #include #include -#include +#include #include #include #include #include #include -#include +#include #include #include #include diff --git a/sw/source/ui/inc/srcedtw.hxx b/sw/source/ui/inc/srcedtw.hxx index 8f4a443..74e1f42 100644 --- a/sw/source/ui/inc/srcedtw.hxx +++ b/sw/source/ui/inc/srcedtw.hxx @@ -32,7 +32,7 @@ #include #include -#include +#include #include namespace com { namespace sun { namespace star { namespace beans { diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index 77717fd..daa5176 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -68,6 +68,7 @@ $(eval $(call gb_Library_add_defs,vcl,\ $(eval $(call gb_Library_use_sdk_api,vcl)) $(eval $(call gb_Library_use_libraries,vcl,\ + svl \ tl \ utl \ sot \ @@ -143,6 +144,14 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\ vcl/source/control/spinfld \ vcl/source/control/tabctrl \ vcl/source/control/throbber \ + vcl/source/edit/vclmedit \ + vcl/source/edit/textdata \ + vcl/source/edit/textdoc \ + vcl/source/edit/texteng \ + vcl/source/edit/textundo \ + vcl/source/edit/textview \ + vcl/source/edit/txtattr \ + vcl/source/edit/xtextedt \ vcl/source/fontsubset/cff \ vcl/source/fontsubset/fontsubset \ vcl/source/fontsubset/gsub \ diff --git a/vcl/Package_inc.mk b/vcl/Package_inc.mk index 0da4b14..c5e6fbf 100644 --- a/vcl/Package_inc.mk +++ b/vcl/Package_inc.mk @@ -151,19 +151,26 @@ $(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/tabctrl.hxx,vcl/tabctrl.hxx)) $(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/tabdlg.hxx,vcl/tabdlg.hxx)) $(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/tabpage.hxx,vcl/tabpage.hxx)) $(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/taskpanelist.hxx,vcl/taskpanelist.hxx)) +$(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/textdata.hxx,vcl/textdata.hxx)) +$(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/texteng.hxx,vcl/texteng.hxx)) +$(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/textview.hxx,vcl/textview.hxx)) $(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/threadex.hxx,vcl/threadex.hxx)) $(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/throbber.hxx,vcl/throbber.hxx)) $(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/timer.hxx,vcl/timer.hxx)) $(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/toolbox.hxx,vcl/toolbox.hxx)) +$(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/txtattr.hxx,vcl/txtattr.hxx)) $(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/unohelp2.hxx,vcl/unohelp2.hxx)) $(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/unohelp.hxx,vcl/unohelp.hxx)) $(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/unowrap.hxx,vcl/unowrap.hxx)) $(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/vclenum.hxx,vcl/vclenum.hxx)) $(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/vclevent.hxx,vcl/vclevent.hxx)) +$(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/vclmedit.hxx,vcl/vclmedit.hxx)) $(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/virdev.hxx,vcl/virdev.hxx)) $(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/waitobj.hxx,vcl/waitobj.hxx)) $(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/wall.hxx,vcl/wall.hxx)) $(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/window.hxx,vcl/window.hxx)) $(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/wrkwin.hxx,vcl/wrkwin.hxx)) +$(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/xtextedt.hxx,vcl/xtextedt.hxx)) + # vim: set noet sw=4 ts=4: diff --git a/vcl/inc/vcl/msgbox.hxx b/vcl/inc/vcl/msgbox.hxx index 1d76e13..2bb73ab 100644 --- a/vcl/inc/vcl/msgbox.hxx +++ b/vcl/inc/vcl/msgbox.hxx @@ -34,7 +34,7 @@ #include #include #include -class FixedText; +class VCLMultiLineEdit; class FixedImage; class CheckBox; @@ -67,7 +67,7 @@ class CheckBox; class VCL_DLLPUBLIC MessBox : public ButtonDialog { protected: - FixedText* mpFixedText; + VCLMultiLineEdit* mpVCLMultiLineEdit; FixedImage* mpFixedImage; XubString maMessText; Image maImage; diff --git a/vcl/inc/vcl/textdata.hxx b/vcl/inc/vcl/textdata.hxx new file mode 100644 index 0000000..4ee0e2f --- /dev/null +++ b/vcl/inc/vcl/textdata.hxx @@ -0,0 +1,172 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef _TEXTDATA_HXX +#define _TEXTDATA_HXX + +#include +#include +#include +#include + +// Fuer Notify, wenn alle Absaetze geloescht wurden... +#define TEXT_PARA_ALL 0xFFFFFFFF + +class TextPaM +{ +private: + sal_uLong mnPara; + sal_uInt16 mnIndex; + +public: + TextPaM() { mnPara = 0, mnIndex = 0; } + TextPaM( sal_uLong nPara, sal_uInt16 nIndex ) { mnPara = nPara, mnIndex = nIndex; } + + sal_uLong GetPara() const { return mnPara; } + sal_uLong& GetPara() { return mnPara; } + + sal_uInt16 GetIndex() const { return mnIndex; } + sal_uInt16& GetIndex() { return mnIndex; } + + inline sal_Bool operator == ( const TextPaM& rPaM ) const; + inline sal_Bool operator != ( const TextPaM& rPaM ) const; + inline sal_Bool operator < ( const TextPaM& rPaM ) const; + inline sal_Bool operator > ( const TextPaM& rPaM ) const; +}; + +inline sal_Bool TextPaM::operator == ( const TextPaM& rPaM ) const +{ + return ( ( mnPara == rPaM.mnPara ) && ( mnIndex == rPaM.mnIndex ) ) ? sal_True : sal_False; +} + +inline sal_Bool TextPaM::operator != ( const TextPaM& rPaM ) const +{ + return !( *this == rPaM ); +} + +inline sal_Bool TextPaM::operator < ( const TextPaM& rPaM ) const +{ + return ( ( mnPara < rPaM.mnPara ) || + ( ( mnPara == rPaM.mnPara ) && mnIndex < rPaM.mnIndex ) ) ? sal_True : sal_False; +} + +inline sal_Bool TextPaM::operator > ( const TextPaM& rPaM ) const +{ + return ( ( mnPara > rPaM.mnPara ) || + ( ( mnPara == rPaM.mnPara ) && mnIndex > rPaM.mnIndex ) ) ? sal_True : sal_False; +} + +class VCL_DLLPUBLIC TextSelection +{ +private: + TextPaM maStartPaM; + TextPaM maEndPaM; + +public: + TextSelection(); + TextSelection( const TextPaM& rPaM ); + TextSelection( const TextPaM& rStart, const TextPaM& rEnd ); + + const TextPaM& GetStart() const { return maStartPaM; } + TextPaM& GetStart() { return maStartPaM; } + + const TextPaM& GetEnd() const { return maEndPaM; } + TextPaM& GetEnd() { return maEndPaM; } + + void Justify(); + + sal_Bool HasRange() const { return maStartPaM != maEndPaM; } + + inline sal_Bool operator == ( const TextSelection& rSel ) const; + inline sal_Bool operator != ( const TextSelection& rSel ) const; +}; + +inline sal_Bool TextSelection::operator == ( const TextSelection& rSel ) const +{ + return ( ( maStartPaM == rSel.maStartPaM ) && ( maEndPaM == rSel.maEndPaM ) ); +} + +inline sal_Bool TextSelection::operator != ( const TextSelection& rSel ) const +{ + return !( *this == rSel ); +} + +#define TEXT_HINT_PARAINSERTED 1 +#define TEXT_HINT_PARAREMOVED 2 +#define TEXT_HINT_PARACONTENTCHANGED 3 +#define TEXT_HINT_TEXTHEIGHTCHANGED 4 +#define TEXT_HINT_FORMATPARA 5 +#define TEXT_HINT_TEXTFORMATTED 6 +#define TEXT_HINT_MODIFIED 7 +#define TEXT_HINT_BLOCKNOTIFICATION_START 8 +#define TEXT_HINT_BLOCKNOTIFICATION_END 9 +#define TEXT_HINT_INPUT_START 10 +#define TEXT_HINT_INPUT_END 11 + +#define TEXT_HINT_VIEWSCROLLED 100 +#define TEXT_HINT_VIEWSELECTIONCHANGED 101 + +class VCL_DLLPUBLIC TextHint : public SfxSimpleHint +{ +private: + sal_uLong mnValue; + +public: + TYPEINFO(); + TextHint( sal_uLong nId ); + TextHint( sal_uLong nId, sal_uLong nValue ); + + sal_uLong GetValue() const { return mnValue; } + void SetValue( sal_uLong n ) { mnValue = n; } +}; + +struct TEIMEInfos +{ + String aOldTextAfterStartPos; + sal_uInt16* pAttribs; + TextPaM aPos; + sal_uInt16 nLen; + sal_Bool bCursor; + sal_Bool bWasCursorOverwrite; + + TEIMEInfos( const TextPaM& rPos, const String& rOldTextAfterStartPos ); + ~TEIMEInfos(); + + void CopyAttribs( const sal_uInt16* pA, sal_uInt16 nL ); + void DestroyAttribs(); +}; + +// ----------------- Wrapper for old Tools List ------------------- + +#include +#include + +template class ToolsList : public ::std::vector< T > +{ +public: + sal_uLong Count() const { return static_cast(::std::vector< T >::size()); } + sal_uLong GetPos( T pObject ) const { return ( ::std::find( this->begin(), this->end(), pObject ) ) - this->begin(); } + T GetObject( sal_uLong nIndex ) const { return (*this)[nIndex]; } + void Insert( T pObject, sal_uLong nPos ) { ::std::vector< T >::insert( this->begin()+nPos, pObject ); } + void Remove( sal_uLong nPos ) { ::std::vector< T >::erase( this->begin()+nPos ); } +}; + +#endif // _TEXTDATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/vcl/texteng.hxx b/vcl/inc/vcl/texteng.hxx new file mode 100644 index 0000000..4eeee73 --- /dev/null +++ b/vcl/inc/vcl/texteng.hxx @@ -0,0 +1,332 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _TEXTENG_HXX +#define _TEXTENG_HXX + +#include + +class TextDoc; +class TextView; +class TextPaM; +class TextSelection; +class TEParaPortions; +class TextAttrib; +class TextCharAttrib; +class TextUndo; +class TextUndoManager; +class EditSelFunctionSet; +class EditSelEngine; +class IdleFormatter; +class TextNode; +class OutputDevice; +class SfxUndoAction; +class KeyEvent; +class Timer; + +namespace svl +{ + class IUndoManager; +} + +class TextLine; +class TETextPortion; +#include +#include +#include +#include +#include + +#include +#include + +struct TEIMEInfos; +class SvtCTLOptions; + +namespace com { +namespace sun { +namespace star { +namespace i18n { + class XBreakIterator; + class XExtendedInputSequenceChecker; +}}}} + +class LocaleDataWrapper; + +enum TxtAlign { TXTALIGN_LEFT, TXTALIGN_CENTER, TXTALIGN_RIGHT }; + +typedef std::vector TextViews; + +class VCL_DLLPUBLIC TextEngine : public SfxBroadcaster +{ + friend class TextView; + friend class TextSelFunctionSet; + friend class ExtTextEngine; + friend class ExtTextView; + + friend class TextUndo; + friend class TextUndoManager; + friend class TextUndoDelPara; + friend class TextUndoConnectParas; + friend class TextUndoSplitPara; + friend class TextUndoInsertChars; + friend class TextUndoRemoveChars; + friend class TextUndoSetAttribs; + +private: + TextDoc* mpDoc; + TEParaPortions* mpTEParaPortions; + OutputDevice* mpRefDev; + + TextViews* mpViews; + TextView* mpActiveView; + + TextUndoManager* mpUndoManager; + + IdleFormatter* mpIdleFormatter; + + TEIMEInfos* mpIMEInfos; + + ::com::sun::star::lang::Locale maLocale; + ::com::sun::star::uno::Reference< ::com::sun::star::i18n::XBreakIterator > mxBreakIterator; + + Rectangle maInvalidRec; + Range maInvalidRange; + + LocaleDataWrapper* mpLocaleDataWrapper; + + Font maFont; + Color maTextColor; + sal_uInt16 mnCharHeight; + sal_uInt16 mnFixCharWidth100; + + sal_uLong mnMaxTextLen; + sal_uLong mnMaxTextWidth; + sal_uLong mnCurTextWidth; + sal_uLong mnCurTextHeight; + sal_uLong mnDefTab; + + TxtAlign meAlign; + + sal_Bool mbIsFormatting : 1; // Semaphore wegen der Hook's + sal_Bool mbFormatted : 1; + sal_Bool mbUpdate : 1; + sal_Bool mbModified : 1; + sal_Bool mbUndoEnabled : 1; + sal_Bool mbIsInUndo : 1; + sal_Bool mbDowning : 1; + sal_Bool mbRightToLeft : 1; + sal_Bool mbHasMultiLineParas : 1; + + TextEngine( const TextEngine& ) : SfxBroadcaster() {} + TextEngine& operator=( const TextEngine& ) { return *this; } + +protected: + + void CursorMoved( sal_uLong nNode ); + void TextModified(); + + void ImpInitDoc(); + void ImpRemoveText(); + TextPaM ImpDeleteText( const TextSelection& rSel ); + TextPaM ImpInsertText( const TextSelection& rSel, sal_Unicode c, sal_Bool bOverwrite = sal_False ); + TextPaM ImpInsertText( const TextSelection& rSel, const String& rText ); + TextPaM ImpInsertParaBreak( const TextSelection& rTextSelection, sal_Bool bKeepEndingAttribs = sal_True ); + TextPaM ImpInsertParaBreak( const TextPaM& rPaM, sal_Bool bKeepEndingAttribs = sal_True ); + void ImpRemoveChars( const TextPaM& rPaM, sal_uInt16 nChars, SfxUndoAction* pCurUndo = 0 ); + TextPaM ImpConnectParagraphs( sal_uLong nLeft, sal_uLong nRight ); + void ImpRemoveParagraph( sal_uLong nPara ); + void ImpInitWritingDirections( sal_uLong nPara ); + LocaleDataWrapper* ImpGetLocaleDataWrapper(); + + // to remain compatible in the minor release we copy the above ImpInsertText + // function and add the extra parameter we need but make sure this function + // gets not exported. First and seconf parameter swapped to have a different signatur. + SAL_DLLPRIVATE TextPaM ImpInsertText( sal_Unicode c, const TextSelection& rSel, sal_Bool bOverwrite = sal_False, sal_Bool bIsUserInput = sal_False ); + // some other new functions needed that must not be exported to remain compatible + SAL_DLLPRIVATE ::com::sun::star::uno::Reference < ::com::sun::star::i18n::XExtendedInputSequenceChecker > GetInputSequenceChecker() const; + SAL_DLLPRIVATE sal_Bool IsInputSequenceCheckingRequired( sal_Unicode c, const TextSelection& rCurSel ) const; + + // Broadcasten bzw. Selektionen anpassen: + void ImpParagraphInserted( sal_uLong nPara ); + void ImpParagraphRemoved( sal_uLong nPara ); + void ImpCharsRemoved( sal_uLong nPara, sal_uInt16 nPos, sal_uInt16 nChars ); + void ImpCharsInserted( sal_uLong nPara, sal_uInt16 nPos, sal_uInt16 nChars ); + void ImpFormattingParagraph( sal_uLong nPara ); + void ImpTextHeightChanged(); + void ImpTextFormatted(); + + DECL_LINK( IdleFormatHdl, void * ); + void CheckIdleFormatter(); + void IdleFormatAndUpdate( TextView* pCurView = 0, sal_uInt16 nMaxTimerRestarts = 5 ); + + sal_Bool CreateLines( sal_uLong nPara ); + void CreateAndInsertEmptyLine( sal_uLong nPara ); + void ImpBreakLine( sal_uLong nPara, TextLine* pLine, TETextPortion* pPortion, sal_uInt16 nPortionStart, long nRemainingWidth ); + sal_uInt16 SplitTextPortion( sal_uLong nPara, sal_uInt16 nPos ); + void CreateTextPortions( sal_uLong nPara, sal_uInt16 nStartPos ); + void RecalcTextPortion( sal_uLong nPara, sal_uInt16 nStartPos, short nNewChars ); + void SeekCursor( sal_uLong nNode, sal_uInt16 nPos, Font& rFont, OutputDevice* pOutDev ); + + void FormatDoc(); + void FormatFullDoc(); + void FormatAndUpdate( TextView* pCurView = 0 ); + sal_Bool IsFormatting() const { return mbIsFormatting; } + void UpdateViews( TextView* pCurView = 0 ); + + void ImpPaint( OutputDevice* pOut, const Point& rStartPos, Rectangle const* pPaintArea, TextSelection const* pPaintRange = 0, TextSelection const* pSelection = 0 ); + + void UpdateSelections(); + + sal_Bool IsFormatted() const { return mbFormatted; } + + sal_uInt16 GetCharPos( sal_uLong nPara, sal_uInt16 nLine, long nDocPosX, sal_Bool bSmart = sal_False ); + Rectangle GetEditCursor( const TextPaM& rPaM, sal_Bool bSpecial, sal_Bool bPreferPortionStart = sal_False ); + sal_uInt16 ImpFindIndex( sal_uLong nPortion, const Point& rPosInPara, sal_Bool bSmart ); + long ImpGetPortionXOffset( sal_uLong nPara, TextLine* pLine, sal_uInt16 nTextPortion ); + long ImpGetXPos( sal_uLong nPara, TextLine* pLine, sal_uInt16 nIndex, sal_Bool bPreferPortionStart = sal_False ); + long ImpGetOutputOffset( sal_uLong nPara, TextLine* pLine, sal_uInt16 nIndex, sal_uInt16 nIndex2 ); + sal_uInt8 ImpGetRightToLeft( sal_uLong nPara, sal_uInt16 nPos, sal_uInt16* pStart = NULL, sal_uInt16* pEnd = NULL ); + void ImpInitLayoutMode( OutputDevice* pOutDev, sal_Bool bDrawingR2LPortion = sal_False ); + TxtAlign ImpGetAlign() const; + + sal_uLong CalcTextHeight(); + sal_uLong CalcParaHeight( sal_uLong nParagraph ) const; + sal_uLong CalcTextWidth( sal_uLong nPara ); + sal_uLong CalcTextWidth( sal_uLong nPara, sal_uInt16 nPortionStart, sal_uInt16 nPortionLen, const Font* pFont = 0 ); + Range GetInvalidYOffsets( sal_uLong nPortion ); + + // Fuer Undo/Redo + void InsertContent( TextNode* pNode, sal_uLong nPara ); + TextPaM SplitContent( sal_uLong nNode, sal_uInt16 nSepPos ); + TextPaM ConnectContents( sal_uLong nLeftNode ); + + // Ans API uebergebene PaM's und Selektionen auf einen gueltigen Bereich einstellen + void ValidateSelection( TextSelection& rSel ) const; + void ValidatePaM( TextPaM& rPaM ) const; + +public: + TextEngine(); + ~TextEngine(); + + void SetText( const String& rStr ); + String GetText( LineEnd aSeparator = LINEEND_LF ) const; + String GetText( const TextSelection& rSel, LineEnd aSeparator = LINEEND_LF ) const; + String GetTextLines( LineEnd aSeparator = LINEEND_LF ) const; + void ReplaceText(const TextSelection& rSel, const String& rText); + + sal_uLong GetTextLen( LineEnd aSeparator = LINEEND_LF ) const; + sal_uLong GetTextLen( const TextSelection& rSel, LineEnd aSeparator = LINEEND_LF ) const; + + void SetFont( const Font& rFont ); + const Font& GetFont() const { return maFont; } + + sal_uInt16 GetDefTab() const; + + void SetLeftMargin( sal_uInt16 n ); + sal_uInt16 GetLeftMargin() const; + + void SetUpdateMode( sal_Bool bUpdate ); + sal_Bool GetUpdateMode() const { return mbUpdate; } + + sal_uInt16 GetViewCount() const; + TextView* GetView( sal_uInt16 nView ) const; + void InsertView( TextView* pTextView ); + void RemoveView( TextView* pTextView ); + TextView* GetActiveView() const; + void SetActiveView( TextView* pView ); + + void SetMaxTextLen( sal_uLong nLen ); + sal_uLong GetMaxTextLen() const { return mnMaxTextLen; } + + void SetMaxTextWidth( sal_uLong nWidth ); + sal_uLong GetMaxTextWidth() const { return mnMaxTextWidth; } + + sal_uLong GetTextHeight() const; + sal_uLong CalcTextWidth(); + sal_uInt16 GetCharHeight() const { return mnCharHeight; } + + sal_uLong GetParagraphCount() const; + String GetText( sal_uLong nParagraph ) const; + sal_uInt16 GetTextLen( sal_uLong nParagraph ) const; + sal_uLong GetTextHeight( sal_uLong nParagraph ) const; + + sal_uInt16 GetLineCount( sal_uLong nParagraph ) const; + sal_uInt16 GetLineLen( sal_uLong nParagraph, sal_uInt16 nLine ) const; + + void SetRightToLeft( sal_Bool bR2L ); + sal_Bool IsRightToLeft() const { return mbRightToLeft; } + + sal_Bool HasUndoManager() const { return mpUndoManager ? sal_True : sal_False; } + ::svl::IUndoManager& + GetUndoManager(); + void UndoActionStart( sal_uInt16 nId = 0 ); + void UndoActionEnd(); + void InsertUndo( TextUndo* pUndo, sal_Bool bTryMerge = sal_False ); + sal_Bool IsInUndo() { return mbIsInUndo; } + void SetIsInUndo( sal_Bool bInUndo ) { mbIsInUndo = bInUndo; } + void ResetUndo(); + + void EnableUndo( sal_Bool bEnable ); + sal_Bool IsUndoEnabled() { return mbUndoEnabled; } + + void SetModified( sal_Bool bModified ) { mbModified = bModified; } + sal_Bool IsModified() const { return mbModified; } + + sal_Bool Read( SvStream& rInput, const TextSelection* pSel = NULL ); + + sal_Bool Write( SvStream& rOutput, const TextSelection* pSel = NULL, sal_Bool bHTML = sal_False ); + + TextPaM GetPaM( const Point& rDocPos, sal_Bool bSmart = sal_True ); + Rectangle PaMtoEditCursor( const TextPaM& rPaM, sal_Bool bSpecial = sal_False ); + String GetWord( const TextPaM& rCursorPos, TextPaM* pStartOfWord = 0 ); + + sal_Bool HasAttrib( sal_uInt16 nWhich ) const; + const TextAttrib* FindAttrib( const TextPaM& rPaM, sal_uInt16 nWhich ) const; + const TextCharAttrib* FindCharAttrib( const TextPaM& rPaM, sal_uInt16 nWhich ) const; + + void RemoveAttribs( sal_uLong nPara, sal_uInt16 nWhich, sal_Bool bIdleFormatAndUpdate ); + void RemoveAttrib( sal_uLong nPara, const TextCharAttrib& rAttrib ); + void RemoveAttribs( sal_uLong nPara, sal_Bool bIdleFormatAndUpdate = sal_True ); + void SetAttrib( const TextAttrib& rAttr, sal_uLong nPara, sal_uInt16 nStart, sal_uInt16 nEnd, sal_Bool bIdleFormatAndUpdate = sal_True ); + + TxtAlign GetTextAlign() const { return meAlign; } + void SetTextAlign( TxtAlign eAlign ); + + void Draw( OutputDevice* pDev, const Point& rPos ); + + void SetLocale( const ::com::sun::star::lang::Locale& rLocale ); + ::com::sun::star::lang::Locale GetLocale(); + ::com::sun::star::uno::Reference< ::com::sun::star::i18n::XBreakIterator > GetBreakIterator(); + + static sal_Bool DoesKeyChangeText( const KeyEvent& rKeyEvent ); + static sal_Bool IsSimpleCharInput( const KeyEvent& rKeyEvent ); +}; + +#endif // _TEXTENG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/vcl/textview.hxx b/vcl/inc/vcl/textview.hxx new file mode 100644 index 0000000..72de5f0 --- /dev/null +++ b/vcl/inc/vcl/textview.hxx @@ -0,0 +1,217 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _TEXTVIEW_HXX +#define _TEXTVIEW_HXX + +#include +#include +#include +#include + +class TextEngine; +class OutputDevice; +class Window; +class Cursor; +class KeyEvent; +class MouseEvent; +class CommandEvent; +class TextSelFunctionSet; +class SelectionEngine; +class VirtualDevice; +struct TextDDInfo; + +namespace com { +namespace sun { +namespace star { +namespace datatransfer { +namespace clipboard { + class XClipboard; +}}}}} + +struct ImpTextView; + +class VCL_DLLPUBLIC TextView : public vcl::unohelper::DragAndDropClient +{ + friend class TextEngine; + friend class TextUndo; + friend class TextUndoManager; + friend class TextSelFunctionSet; + friend class ExtTextView; + +private: + ImpTextView* mpImpl; + + TextView( const TextView& ) : vcl::unohelper::DragAndDropClient() {} + TextView& operator=( const TextView& ) { return *this; } + +protected: + void ShowSelection(); + void HideSelection(); + void ShowSelection( const TextSelection& rSel ); + void ImpShowHideSelection( sal_Bool bShow, const TextSelection* pRange = NULL ); + + TextSelection ImpMoveCursor( const KeyEvent& rKeyEvent ); + TextPaM ImpDelete( sal_uInt8 nMode, sal_uInt8 nDelMode ); + void ImpSetSelection( const TextSelection& rNewSel, sal_Bool bUI ); + sal_Bool IsInSelection( const TextPaM& rPaM ); + + void ImpPaint( OutputDevice* pOut, const Point& rStartPos, Rectangle const* pPaintArea, TextSelection const* pPaintRange = 0, TextSelection const* pSelection = 0 ); + void ImpPaint( const Rectangle& rRect, sal_Bool bUseVirtDev ); + void ImpShowCursor( sal_Bool bGotoCursor, sal_Bool bForceVisCursor, sal_Bool bEndKey ); + void ImpHighlight( const TextSelection& rSel ); + void ImpSetSelection( const TextSelection& rSelection ); + Point ImpGetOutputStartPos( const Point& rStartDocPos ) const; + + void ImpHideDDCursor(); + void ImpShowDDCursor(); + + bool ImplTruncateNewText( rtl::OUString& rNewText ) const; + sal_Bool ImplCheckTextLen( const String& rNewText ); + + VirtualDevice* GetVirtualDevice(); + + // DragAndDropClient + virtual void dragGestureRecognized( const ::com::sun::star::datatransfer::dnd::DragGestureEvent& dge ) throw (::com::sun::star::uno::RuntimeException); + virtual void dragDropEnd( const ::com::sun::star::datatransfer::dnd::DragSourceDropEvent& dsde ) throw (::com::sun::star::uno::RuntimeException); + virtual void drop( const ::com::sun::star::datatransfer::dnd::DropTargetDropEvent& dtde ) throw (::com::sun::star::uno::RuntimeException); + virtual void dragEnter( const ::com::sun::star::datatransfer::dnd::DropTargetDragEnterEvent& dtdee ) throw (::com::sun::star::uno::RuntimeException); + virtual void dragExit( const ::com::sun::star::datatransfer::dnd::DropTargetEvent& dte ) throw (::com::sun::star::uno::RuntimeException); + virtual void dragOver( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& dtde ) throw (::com::sun::star::uno::RuntimeException); + + using DragAndDropClient::dragEnter; + using DragAndDropClient::dragExit; + using DragAndDropClient::dragOver; + +public: + TextView( TextEngine* pEng, Window* pWindow ); + virtual ~TextView(); + + TextEngine* GetTextEngine() const; + Window* GetWindow() const; + + void Invalidate(); + void Scroll( long nHorzScroll, long nVertScroll ); + + void ShowCursor( sal_Bool bGotoCursor = sal_True, sal_Bool bForceVisCursor = sal_True ); + void HideCursor(); + + void EnableCursor( sal_Bool bEnable ); + sal_Bool IsCursorEnabled() const; + + const TextSelection& GetSelection() const; + TextSelection& GetSelection(); + void SetSelection( const TextSelection& rNewSel ); + void SetSelection( const TextSelection& rNewSel, sal_Bool bGotoCursor ); + sal_Bool HasSelection() const; + + String GetSelected(); + String GetSelected( LineEnd aSeparator ); + void DeleteSelected(); + + void InsertNewText( const rtl::OUString& rNew, sal_Bool bSelect = sal_False ); + // deprecated: use InsertNewText instead + void InsertText( const String& rNew, sal_Bool bSelect = sal_False ); + + sal_Bool KeyInput( const KeyEvent& rKeyEvent ); + void Paint( const Rectangle& rRect ); + void MouseButtonUp( const MouseEvent& rMouseEvent ); + void MouseButtonDown( const MouseEvent& rMouseEvent ); + void MouseMove( const MouseEvent& rMouseEvent ); + void Command( const CommandEvent& rCEvt ); + + void Cut(); + void Copy(); + void Paste(); + + void Copy( ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboard >& rxClipboard ); + void Paste( ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboard >& rxClipboard ); + + void Undo(); + void Redo(); + + sal_Bool Read( SvStream& rInput ); + + void SetStartDocPos( const Point& rPos ); + const Point& GetStartDocPos() const; + + Point GetDocPos( const Point& rWindowPos ) const; + Point GetWindowPos( const Point& rDocPos ) const; + + void SetInsertMode( sal_Bool bInsert ); + sal_Bool IsInsertMode() const; + + void SetAutoIndentMode( sal_Bool bAutoIndent ); + + void SetReadOnly( sal_Bool bReadOnly ); + sal_Bool IsReadOnly() const; + + void SetAutoScroll( sal_Bool bAutoScroll ); + sal_Bool IsAutoScroll() const; + + sal_Bool SetCursorAtPoint( const Point& rPointPixel ); + sal_Bool IsSelectionAtPoint( const Point& rPointPixel ); + + void SetPaintSelection( sal_Bool bPaint); + + void EraseVirtualDevice(); + + // aus dem protected Teil hierher verschoben + // F�r 'SvtXECTextCursor' (TL). Mu� ggf nochmal anders gel�st werden. + TextPaM PageUp( const TextPaM& rPaM ); + TextPaM PageDown( const TextPaM& rPaM ); + TextPaM CursorUp( const TextPaM& rPaM ); + TextPaM CursorDown( const TextPaM& rPaM ); + TextPaM CursorLeft( const TextPaM& rPaM, sal_uInt16 nCharacterIteratorMode ); + TextPaM CursorRight( const TextPaM& rPaM, sal_uInt16 nCharacterIteratorMode ); + TextPaM CursorWordLeft( const TextPaM& rPaM ); + TextPaM CursorWordRight( const TextPaM& rPaM ); + TextPaM CursorStartOfLine( const TextPaM& rPaM ); + TextPaM CursorEndOfLine( const TextPaM& rPaM ); + TextPaM CursorStartOfParagraph( const TextPaM& rPaM ); + TextPaM CursorEndOfParagraph( const TextPaM& rPaM ); + TextPaM CursorStartOfDoc(); + TextPaM CursorEndOfDoc(); + + /** + Drag and Drop, deleting and selection regards all text that has an attribute + TEXTATTR_PROTECTED set as one entitity. Drag and dropped text is automatically + attibuted as protected. + */ + void SupportProtectAttribute(sal_Bool bSupport); + + /** + Returns the number in paragraph of the line in which the cursor is blinking + if enabled, -1 otherwise. + */ + sal_Int32 GetLineNumberOfCursorInSelection() const; +}; + +#endif // _TEXTVIEW_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/vcl/txtattr.hxx b/vcl/inc/vcl/txtattr.hxx new file mode 100644 index 0000000..695dfc7 --- /dev/null +++ b/vcl/inc/vcl/txtattr.hxx @@ -0,0 +1,236 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _TXTATTR_HXX +#define _TXTATTR_HXX + +#include +#include +#include +#include +#include + +class Font; + +#define TEXTATTR_INVALID 0 +#define TEXTATTR_FONTCOLOR 1 +#define TEXTATTR_HYPERLINK 2 +#define TEXTATTR_FONTWEIGHT 3 + +#define TEXTATTR_USER_START 1000 //start id for user defined text attributes +#define TEXTATTR_PROTECTED 4 + + +class VCL_DLLPUBLIC TextAttrib +{ +private: + sal_uInt16 mnWhich; + +protected: + TextAttrib( sal_uInt16 nWhich ) { mnWhich = nWhich; } + TextAttrib( const TextAttrib& rAttr ) { mnWhich = rAttr.mnWhich; } + +public: + + virtual ~TextAttrib(); + + sal_uInt16 Which() const { return mnWhich; } + virtual void SetFont( Font& rFont ) const = 0; + virtual TextAttrib* Clone() const = 0; + + virtual int operator==( const TextAttrib& rAttr ) const = 0; + int operator!=( const TextAttrib& rAttr ) const + { return !(*this == rAttr ); } +}; + + + +class VCL_DLLPUBLIC TextAttribFontColor : public TextAttrib +{ +private: + Color maColor; + +public: + TextAttribFontColor( const Color& rColor ); + TextAttribFontColor( const TextAttribFontColor& rAttr ); + ~TextAttribFontColor(); + + const Color& GetColor() const { return maColor; } + + virtual void SetFont( Font& rFont ) const; + virtual TextAttrib* Clone() const; + virtual int operator==( const TextAttrib& rAttr ) const; + +}; + +class VCL_DLLPUBLIC TextAttribFontWeight : public TextAttrib +{ +private: + FontWeight meWeight; + +public: + TextAttribFontWeight( FontWeight eWeight ); + TextAttribFontWeight( const TextAttribFontWeight& rAttr ); + ~TextAttribFontWeight(); + + virtual void SetFont( Font& rFont ) const; + virtual TextAttrib* Clone() const; + virtual int operator==( const TextAttrib& rAttr ) const; + + inline FontWeight getFontWeight() const { return meWeight; } +}; + + +class TextAttribHyperLink : public TextAttrib +{ +private: + XubString maURL; + XubString maDescription; + Color maColor; + +public: + TextAttribHyperLink( const TextAttribHyperLink& rAttr ); + ~TextAttribHyperLink(); + + void SetURL( const XubString& rURL ) { maURL = rURL; } + const XubString& GetURL() const { return maURL; } + + void SetDescription( const XubString& rDescr ) { maDescription = rDescr; } + const XubString& GetDescription() const { return maDescription; } + + void SetColor( const Color& rColor ) { maColor = rColor; } + const Color& GetColor() const { return maColor; } + + virtual void SetFont( Font& rFont ) const; + virtual TextAttrib* Clone() const; + virtual int operator==( const TextAttrib& rAttr ) const; +}; + +class VCL_DLLPUBLIC TextAttribProtect : public TextAttrib +{ +public: + TextAttribProtect(); + TextAttribProtect( const TextAttribProtect& rAttr ); + ~TextAttribProtect(); + + virtual void SetFont( Font& rFont ) const; + virtual TextAttrib* Clone() const; + virtual int operator==( const TextAttrib& rAttr ) const; + +}; + + +class TextCharAttrib +{ +private: + TextAttrib* mpAttr; + sal_uInt16 mnStart; + sal_uInt16 mnEnd; + +protected: + +public: + + TextCharAttrib( const TextAttrib& rAttr, sal_uInt16 nStart, sal_uInt16 nEnd ); + TextCharAttrib( const TextCharAttrib& rTextCharAttrib ); + ~TextCharAttrib(); + + const TextAttrib& GetAttr() const { return *mpAttr; } + + sal_uInt16 Which() const { return mpAttr->Which(); } + + sal_uInt16 GetStart() const { return mnStart; } + sal_uInt16& GetStart() { return mnStart; } + + sal_uInt16 GetEnd() const { return mnEnd; } + sal_uInt16& GetEnd() { return mnEnd; } + + inline sal_uInt16 GetLen() const; + + inline void MoveForward( sal_uInt16 nDiff ); + inline void MoveBackward( sal_uInt16 nDiff ); + + inline void Expand( sal_uInt16 nDiff ); + inline void Collaps( sal_uInt16 nDiff ); + + inline sal_Bool IsIn( sal_uInt16 nIndex ); + inline sal_Bool IsInside( sal_uInt16 nIndex ); + inline sal_Bool IsEmpty(); + +}; + +inline sal_uInt16 TextCharAttrib::GetLen() const +{ + DBG_ASSERT( mnEnd >= mnStart, "TextCharAttrib: nEnd < nStart!" ); + return mnEnd-mnStart; +} + +inline void TextCharAttrib::MoveForward( sal_uInt16 nDiff ) +{ + DBG_ASSERT( ((long)mnEnd + nDiff) <= 0xFFFF, "TextCharAttrib: MoveForward?!" ); + mnStart = mnStart + nDiff; + mnEnd = mnEnd + nDiff; +} + +inline void TextCharAttrib::MoveBackward( sal_uInt16 nDiff ) +{ + DBG_ASSERT( ((long)mnStart - nDiff) >= 0, "TextCharAttrib: MoveBackward?!" ); + mnStart = mnStart - nDiff; + mnEnd = mnEnd - nDiff; +} + +inline void TextCharAttrib::Expand( sal_uInt16 nDiff ) +{ + DBG_ASSERT( ( ((long)mnEnd + nDiff) <= (long)0xFFFF ), "TextCharAttrib: Expand?!" ); + mnEnd = mnEnd + nDiff; +} + +inline void TextCharAttrib::Collaps( sal_uInt16 nDiff ) +{ + DBG_ASSERT( (long)mnEnd - nDiff >= (long)mnStart, "TextCharAttrib: Collaps?!" ); + mnEnd = mnEnd - nDiff; +} + +inline sal_Bool TextCharAttrib::IsIn( sal_uInt16 nIndex ) +{ + return ( ( mnStart <= nIndex ) && ( mnEnd >= nIndex ) ); +} + +inline sal_Bool TextCharAttrib::IsInside( sal_uInt16 nIndex ) +{ + return ( ( mnStart < nIndex ) && ( mnEnd > nIndex ) ); +} + +inline sal_Bool TextCharAttrib::IsEmpty() +{ + return mnStart == mnEnd; +} + +#endif // _TXTATTR_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/vcl/vclmedit.hxx b/vcl/inc/vcl/vclmedit.hxx new file mode 100644 index 0000000..b9711cf --- /dev/null +++ b/vcl/inc/vcl/vclmedit.hxx @@ -0,0 +1,149 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _VCLMEDIT_HXX +#define _VCLMEDIT_HXX + +#include +#include +#include + + +class ImpSvMEdit; +class Timer; +class ExtTextEngine; +class ExtTextView; + +class VCL_DLLPUBLIC VCLMultiLineEdit : public Edit +{ +private: + ImpSvMEdit* pImpSvMEdit; + + XubString aSaveValue; + Link aModifyHdlLink; + + Timer* pUpdateDataTimer; + Link aUpdateDataHdlLink; + +protected: + + DECL_LINK( ImpUpdateDataHdl, void* ); + void StateChanged( StateChangedType nType ); + void DataChanged( const DataChangedEvent& rDCEvt ); + virtual long PreNotify( NotifyEvent& rNEvt ); + long Notify( NotifyEvent& rNEvt ); + using Control::ImplInitSettings; + void ImplInitSettings( sal_Bool bFont, sal_Bool bForeground, sal_Bool bBackground ); + WinBits ImplInitStyle( WinBits nStyle ); + + ExtTextEngine* GetTextEngine() const; + ExtTextView* GetTextView() const; + ScrollBar* GetVScrollBar() const; + +public: + VCLMultiLineEdit( Window* pParent, WinBits nWinStyle = WB_LEFT | WB_BORDER ); + VCLMultiLineEdit( Window* pParent, const ResId& rResId ); + virtual ~VCLMultiLineEdit(); + + + virtual void Modify(); + virtual void UpdateData(); + + virtual void SetModifyFlag(); + virtual void ClearModifyFlag(); + virtual sal_Bool IsModified() const; + + virtual void EnableUpdateData( sal_uLong nTimeout = EDIT_UPDATEDATA_TIMEOUT ); + virtual void DisableUpdateData() { delete pUpdateDataTimer; pUpdateDataTimer = NULL; } + virtual sal_uLong IsUpdateDataEnabled() const; + + virtual void SetReadOnly( sal_Bool bReadOnly = sal_True ); + virtual sal_Bool IsReadOnly() const; + + void EnableFocusSelectionHide( sal_Bool bHide ); + + virtual void SetMaxTextLen( xub_StrLen nMaxLen = 0 ); + virtual xub_StrLen GetMaxTextLen() const; + + virtual void SetSelection( const Selection& rSelection ); + virtual const Selection& GetSelection() const; + + virtual void ReplaceSelected( const XubString& rStr ); + virtual void DeleteSelected(); + virtual XubString GetSelected() const; + virtual XubString GetSelected( LineEnd aSeparator ) const; + + virtual void Cut(); + virtual void Copy(); + virtual void Paste(); + + virtual void SetText( const XubString& rStr ); + virtual void SetText( const XubString& rStr, const Selection& rNewSelection ) + { SetText( rStr ); SetSelection( rNewSelection ); } + String GetText() const; + String GetText( LineEnd aSeparator ) const; + String GetTextLines( LineEnd aSeparator ) const; + + void SetRightToLeft( sal_Bool bRightToLeft ); + sal_Bool IsRightToLeft() const; + + void SaveValue() { aSaveValue = GetText(); } + const XubString& GetSavedValue() const { return aSaveValue; } + + void SetModifyHdl( const Link& rLink ) { aModifyHdlLink = rLink; } + const Link& GetModifyHdl() const { return aModifyHdlLink; } + + void SetUpdateDataHdl( const Link& rLink ) { aUpdateDataHdlLink = rLink; } + const Link& GetUpdateDataHdl() const { return aUpdateDataHdlLink; } + + virtual void Resize(); + virtual void GetFocus(); + + Size CalcMinimumSize() const; + Size CalcAdjustedSize( const Size& rPrefSize ) const; + using Edit::CalcSize; + Size CalcSize( sal_uInt16 nColumns, sal_uInt16 nLines ) const; + void GetMaxVisColumnsAndLines( sal_uInt16& rnCols, sal_uInt16& rnLines ) const; + + void Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, sal_uLong nFlags ); + + void SetLeftMargin( sal_uInt16 n ); + + void DisableSelectionOnFocus(); + + void SetTextSelectable( sal_Bool bTextSelectable ); +}; + +inline sal_uLong VCLMultiLineEdit::IsUpdateDataEnabled() const +{ + return pUpdateDataTimer ? pUpdateDataTimer->GetTimeout() : 0; +} + +#endif //_VCLMEDIT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/vcl/xtextedt.hxx b/vcl/inc/vcl/xtextedt.hxx new file mode 100644 index 0000000..b763e37 --- /dev/null +++ b/vcl/inc/vcl/xtextedt.hxx @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef _XTEXTEDT_HXX +#define _XTEXTEDT_HXX + +#include +#include +#include + +namespace com { +namespace sun { +namespace star { +namespace util { + struct SearchOptions; +}}}} + +class VCL_DLLPUBLIC ExtTextEngine : public TextEngine +{ +private: + String maGroupChars; + +public: + ExtTextEngine(); + ~ExtTextEngine(); + + const String& GetGroupChars() const { return maGroupChars; } + void SetGroupChars( const String& r ) { maGroupChars = r; } + TextSelection MatchGroup( const TextPaM& rCursor ) const; + + sal_Bool Search( TextSelection& rSel, const ::com::sun::star::util::SearchOptions& rSearchOptions, sal_Bool bForward = sal_True ); +}; + +class VCL_DLLPUBLIC ExtTextView : public TextView +{ +protected: + sal_Bool ImpIndentBlock( sal_Bool bRight ); + +public: + ExtTextView( ExtTextEngine* pEng, Window* pWindow ); + ~ExtTextView(); + + sal_Bool MatchGroup(); + + sal_Bool Search( const ::com::sun::star::util::SearchOptions& rSearchOptions, sal_Bool bForward ); + sal_uInt16 Replace( const ::com::sun::star::util::SearchOptions& rSearchOptions, sal_Bool bAll, sal_Bool bForward ); + + sal_Bool IndentBlock(); + sal_Bool UnindentBlock(); +}; + +#endif // _XTEXTEDT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/edit/textdat2.hxx b/vcl/source/edit/textdat2.hxx new file mode 100644 index 0000000..c52d33e --- /dev/null +++ b/vcl/source/edit/textdat2.hxx @@ -0,0 +1,312 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#ifndef _TEXTDAT2_HXX +#define _TEXTDAT2_HXX + +#include +#include +#include + +#include + +class TextNode; +class TextView; + +#define PORTIONKIND_TEXT 0 +#define PORTIONKIND_TAB 1 + +#define DELMODE_SIMPLE 0 +#define DELMODE_RESTOFWORD 1 +#define DELMODE_RESTOFCONTENT 2 + +#define DEL_LEFT 1 +#define DEL_RIGHT 2 +#define TRAVEL_X_DONTKNOW 0xFFFF +#define MAXCHARSINPARA 0x3FFF-CHARPOSGROW + +#define LINE_SEP 0x0A + + +class TETextPortion +{ +private: + sal_uInt16 nLen; + long nWidth; + sal_uInt8 nKind; + sal_uInt8 nRightToLeft; + + TETextPortion() { nLen = 0; nKind = PORTIONKIND_TEXT; nWidth = -1; nRightToLeft = 0;} + +public: + TETextPortion( sal_uInt16 nL ) { + nLen = nL; + nKind = PORTIONKIND_TEXT; + nWidth= -1; + nRightToLeft = 0; + } + + sal_uInt16 GetLen() const { return nLen; } + sal_uInt16& GetLen() { return nLen; } + + long GetWidth()const { return nWidth; } + long& GetWidth() { return nWidth; } + + sal_uInt8 GetKind() const { return nKind; } + sal_uInt8& GetKind() { return nKind; } + + sal_uInt8 GetRightToLeft() const { return nRightToLeft; } + sal_uInt8& GetRightToLeft() { return nRightToLeft; } + sal_Bool IsRightToLeft() const { return (nRightToLeft&1); } + + sal_Bool HasValidSize() const { return nWidth != (-1); } +}; + + + +typedef std::vector TextPortionArray; + +class TETextPortionList : public TextPortionArray +{ +public: + TETextPortionList(); + ~TETextPortionList(); + + void Reset(); + sal_uInt16 FindPortion( sal_uInt16 nCharPos, sal_uInt16& rPortionStart, sal_Bool bPreferStartingPortion = sal_False ); + sal_uInt16 GetPortionStartIndex( sal_uInt16 nPortion ); + void DeleteFromPortion( sal_uInt16 nDelFrom ); +}; + +struct TEWritingDirectionInfo +{ + sal_uInt8 nType; + sal_uInt16 nStartPos; + sal_uInt16 nEndPos; + TEWritingDirectionInfo( sal_uInt8 _Type, sal_uInt16 _Start, sal_uInt16 _End ) + { + nType = _Type; + nStartPos = _Start; + nEndPos = _End; + } +}; + +class TextLine +{ +private: + sal_uInt16 mnStart; + sal_uInt16 mnEnd; + sal_uInt16 mnStartPortion; + sal_uInt16 mnEndPortion; + + short mnStartX; + + sal_Bool mbInvalid; // fuer geschickte Formatierung/Ausgabe + +public: + TextLine() { + mnStart = mnEnd = 0; + mnStartPortion = mnEndPortion = 0; + mnStartX = 0; + mbInvalid = sal_True; + } + + sal_Bool IsIn( sal_uInt16 nIndex ) const + { return ( (nIndex >= mnStart ) && ( nIndex < mnEnd ) ); } + + sal_Bool IsIn( sal_uInt16 nIndex, sal_Bool bInclEnd ) const + { return ( ( nIndex >= mnStart ) && ( bInclEnd ? ( nIndex <= mnEnd ) : ( nIndex < mnEnd ) ) ); } + + void SetStart( sal_uInt16 n ) { mnStart = n; } + sal_uInt16 GetStart() const { return mnStart; } + sal_uInt16& GetStart() { return mnStart; } + + void SetEnd( sal_uInt16 n ) { mnEnd = n; } + sal_uInt16 GetEnd() const { return mnEnd; } + sal_uInt16& GetEnd() { return mnEnd; } + + void SetStartPortion( sal_uInt16 n ) { mnStartPortion = n; } + sal_uInt16 GetStartPortion() const { return mnStartPortion; } + sal_uInt16& GetStartPortion() { return mnStartPortion; } + + void SetEndPortion( sal_uInt16 n ) { mnEndPortion = n; } + sal_uInt16 GetEndPortion() const { return mnEndPortion; } + sal_uInt16& GetEndPortion() { return mnEndPortion; } + + sal_uInt16 GetLen() const { return mnEnd - mnStart; } + + sal_Bool IsInvalid() const { return mbInvalid; } + sal_Bool IsValid() const { return !mbInvalid; } + void SetInvalid() { mbInvalid = sal_True; } + void SetValid() { mbInvalid = sal_False; } + + sal_Bool IsEmpty() const { return (mnEnd > mnStart) ? sal_False : sal_True; } + + short GetStartX() const { return mnStartX; } + void SetStartX( short n ) { mnStartX = n; } + + inline sal_Bool operator == ( const TextLine& rLine ) const; + inline sal_Bool operator != ( const TextLine& rLine ) const; +}; + +class TextLines : public std::vector { +public: + ~TextLines() + { + for( iterator it = begin(); it != end(); ++it ) + delete *it; + } +}; + +inline sal_Bool TextLine::operator == ( const TextLine& rLine ) const +{ + return ( ( mnStart == rLine.mnStart ) && + ( mnEnd == rLine.mnEnd ) && + ( mnStartPortion == rLine.mnStartPortion ) && + ( mnEndPortion == rLine.mnEndPortion ) ); +} + +inline sal_Bool TextLine::operator != ( const TextLine& rLine ) const +{ + return !( *this == rLine ); +} + + + +class TEParaPortion +{ +private: + TextNode* mpNode; + + TextLines maLines; + TETextPortionList maTextPortions; + std::vector maWritingDirectionInfos; + + + sal_uInt16 mnInvalidPosStart; + short mnInvalidDiff; + + sal_Bool mbInvalid; + sal_Bool mbSimple; // nur lineares Tippen + + + TEParaPortion( const TEParaPortion& ) {;} + +public: + TEParaPortion( TextNode* pNode ); + ~TEParaPortion(); + + + sal_Bool IsInvalid() const { return mbInvalid; } + sal_Bool IsSimpleInvalid() const { return mbSimple; } + void SetNotSimpleInvalid() { mbSimple = sal_False; } + void SetValid() { mbInvalid = sal_False; mbSimple = sal_True;} + + void MarkInvalid( sal_uInt16 nStart, short nDiff); + void MarkSelectionInvalid( sal_uInt16 nStart, sal_uInt16 nEnd ); + + sal_uInt16 GetInvalidPosStart() const { return mnInvalidPosStart; } + short GetInvalidDiff() const { return mnInvalidDiff; } + + TextNode* GetNode() const { return mpNode; } + TextLines& GetLines() { return maLines; } + TETextPortionList& GetTextPortions() { return maTextPortions; } + std::vector& GetWritingDirectionInfos() { return maWritingDirectionInfos; } + + + sal_uInt16 GetLineNumber( sal_uInt16 nIndex, sal_Bool bInclEnd ); + void CorrectValuesBehindLastFormattedLine( sal_uInt16 nLastFormattedLine ); +}; + + +class TEParaPortions : public ToolsList +{ +public: + TEParaPortions(); + ~TEParaPortions(); + void Reset(); +}; + + +class TextSelFunctionSet: public FunctionSet +{ +private: + TextView* mpView; + +public: + TextSelFunctionSet( TextView* pView ); + + virtual void BeginDrag(); + + virtual void CreateAnchor(); + + virtual sal_Bool SetCursorAtPoint( const Point& rPointPixel, sal_Bool bDontSelectAtCursor = sal_False ); + + virtual sal_Bool IsSelectionAtPoint( const Point& rPointPixel ); + virtual void DeselectAll(); + + virtual void DeselectAtPoint( const Point& ); + virtual void DestroyAnchor(); +}; + + +class IdleFormatter : public Timer +{ +private: + TextView* mpView; + sal_uInt16 mnRestarts; + +public: + IdleFormatter(); + ~IdleFormatter(); + + void DoIdleFormat( TextView* pV, sal_uInt16 nMaxRestarts ); + void ForceTimeout(); + TextView* GetView() { return mpView; } +}; + +struct TextDDInfo +{ + Cursor maCursor; + TextPaM maDropPos; + + sal_Bool mbStarterOfDD; + sal_Bool mbVisCursor; + + TextDDInfo() + { + maCursor.SetStyle( CURSOR_SHADOW ); + mbStarterOfDD = sal_False; + mbVisCursor = sal_False; + } +}; + +#endif // _TEXTDAT2_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/edit/textdata.cxx b/vcl/source/edit/textdata.cxx new file mode 100644 index 0000000..79f28f3 --- /dev/null +++ b/vcl/source/edit/textdata.cxx @@ -0,0 +1,345 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include +#include + +#include + + +// ------------------------------------------------------------------------- +// (+) class TextSelection +// ------------------------------------------------------------------------- + +TextSelection::TextSelection() +{ +} + +TextSelection::TextSelection( const TextPaM& rPaM ) : + maStartPaM( rPaM ), maEndPaM( rPaM ) +{ +} + +TextSelection::TextSelection( const TextPaM& rStart, const TextPaM& rEnd ) : + maStartPaM( rStart ), maEndPaM( rEnd ) +{ +} + +void TextSelection::Justify() +{ + if ( maEndPaM < maStartPaM ) + { + TextPaM aTemp( maStartPaM ); + maStartPaM = maEndPaM; + maEndPaM = aTemp; + } +} + + +// ------------------------------------------------------------------------- +// (+) class TETextPortionList +// ------------------------------------------------------------------------- +TETextPortionList::TETextPortionList() +{ +} + +TETextPortionList::~TETextPortionList() +{ + Reset(); +} + +void TETextPortionList::Reset() +{ + for ( iterator it = begin(); it != end(); ++it ) + delete *it; + clear(); +} + +void TETextPortionList::DeleteFromPortion( sal_uInt16 nDelFrom ) +{ + DBG_ASSERT( ( nDelFrom < size() ) || ( (nDelFrom == 0) && (size() == 0) ), "DeleteFromPortion: Out of range" ); + for ( iterator it = begin() + nDelFrom; it != end(); ++it ) + delete *it; + erase( begin() + nDelFrom, end() ); +} + +sal_uInt16 TETextPortionList::FindPortion( sal_uInt16 nCharPos, sal_uInt16& nPortionStart, sal_Bool bPreferStartingPortion ) +{ + // Bei nCharPos an Portion-Grenze wird die linke Portion gefunden + sal_uInt16 nTmpPos = 0; + for ( sal_uInt16 nPortion = 0; nPortion < size(); nPortion++ ) + { + TETextPortion* pPortion = operator[]( nPortion ); + nTmpPos = nTmpPos + pPortion->GetLen(); + if ( nTmpPos >= nCharPos ) + { + // take this one if we don't prefer the starting portion, or if it's the last one + if ( ( nTmpPos != nCharPos ) || !bPreferStartingPortion || ( nPortion == size() - 1 ) ) + { + nPortionStart = nTmpPos - pPortion->GetLen(); + return nPortion; + } + } + } + OSL_FAIL( "FindPortion: Nicht gefunden!" ); + return ( size() - 1 ); +} + + +// ------------------------------------------------------------------------- +// (+) class TEParaPortion +// ------------------------------------------------------------------------- +TEParaPortion::TEParaPortion( TextNode* pN ) +{ + mpNode = pN; + mnInvalidPosStart = mnInvalidDiff = 0; + mbInvalid = sal_True; + mbSimple = sal_False; +} + +TEParaPortion::~TEParaPortion() +{ +} + +void TEParaPortion::MarkInvalid( sal_uInt16 nStart, short nDiff ) +{ + if ( mbInvalid == sal_False ) + { + mnInvalidPosStart = ( nDiff >= 0 ) ? nStart : ( nStart + nDiff ); + mnInvalidDiff = nDiff; + } + else + { + // Einfaches hintereinander tippen + if ( ( nDiff > 0 ) && ( mnInvalidDiff > 0 ) && + ( ( mnInvalidPosStart+mnInvalidDiff ) == nStart ) ) + { + mnInvalidDiff = mnInvalidDiff + nDiff; + } + // Einfaches hintereinander loeschen + else if ( ( nDiff < 0 ) && ( mnInvalidDiff < 0 ) && ( mnInvalidPosStart == nStart ) ) + { + mnInvalidPosStart = mnInvalidPosStart + nDiff; + mnInvalidDiff = mnInvalidDiff + nDiff; + } + else + { + DBG_ASSERT( ( nDiff >= 0 ) || ( (nStart+nDiff) >= 0 ), "MarkInvalid: Diff out of Range" ); + mnInvalidPosStart = Min( mnInvalidPosStart, (sal_uInt16) ( (nDiff < 0) ? nStart+nDiff : nDiff ) ); + mnInvalidDiff = 0; + mbSimple = sal_False; + } + } + + maWritingDirectionInfos.clear(); + + mbInvalid = sal_True; +} + +void TEParaPortion::MarkSelectionInvalid( sal_uInt16 nStart, sal_uInt16 /*nEnd*/ ) +{ + if ( mbInvalid == sal_False ) + { + mnInvalidPosStart = nStart; +// nInvalidPosEnd = nEnd; + } + else + { + mnInvalidPosStart = Min( mnInvalidPosStart, nStart ); +// nInvalidPosEnd = pNode->Len(); + } + + maWritingDirectionInfos.clear(); + + mnInvalidDiff = 0; + mbInvalid = sal_True; + mbSimple = sal_False; +} + +sal_uInt16 TEParaPortion::GetLineNumber( sal_uInt16 nChar, sal_Bool bInclEnd ) +{ + for ( sal_uInt16 nLine = 0; nLine < maLines.size(); nLine++ ) + { + TextLine* pLine = maLines[ nLine ]; + if ( ( bInclEnd && ( pLine->GetEnd() >= nChar ) ) || + ( pLine->GetEnd() > nChar ) ) + { + return nLine; + } + } + + // Then it should be at the end of the last line + OSL_ENSURE(nChar == maLines[maLines.size() - 1]->GetEnd(), "wrong Index"); + OSL_ENSURE(!bInclEnd, "Line not found: FindLine"); + return ( maLines.size() - 1 ); +} + + +void TEParaPortion::CorrectValuesBehindLastFormattedLine( sal_uInt16 nLastFormattedLine ) +{ + sal_uInt16 nLines = maLines.size(); + DBG_ASSERT( nLines, "CorrectPortionNumbersFromLine: Leere Portion?" ); + if ( nLastFormattedLine < ( nLines - 1 ) ) + { + const TextLine* pLastFormatted = maLines[ nLastFormattedLine ]; + const TextLine* pUnformatted = maLines[ nLastFormattedLine+1 ]; + short nPortionDiff = pUnformatted->GetStartPortion() - pLastFormatted->GetEndPortion(); + short nTextDiff = pUnformatted->GetStart() - pLastFormatted->GetEnd(); + nTextDiff++; // LastFormatted->GetEnd() war incl. => 1 zuviel abgezogen! + + // Die erste unformatierte muss genau eine Portion hinter der letzten der + // formatierten beginnen: + // Wenn in der geaenderten Zeile eine Portion gesplittet wurde, + // kann nLastEnd > nNextStart sein! + short nPDiff = sal::static_int_cast< short >(-( nPortionDiff-1 )); + short nTDiff = sal::static_int_cast< short >(-( nTextDiff-1 )); + if ( nPDiff || nTDiff ) + { + for ( sal_uInt16 nL = nLastFormattedLine+1; nL < nLines; nL++ ) + { + TextLine* pLine = maLines[ nL ]; + + pLine->GetStartPortion() = pLine->GetStartPortion() + nPDiff; + pLine->GetEndPortion() = pLine->GetEndPortion() + nPDiff; + + pLine->GetStart() = pLine->GetStart() + nTDiff; + pLine->GetEnd() = pLine->GetEnd() + nTDiff; + + pLine->SetValid(); + } + } + } +} + +// ------------------------------------------------------------------------- +// (+) class TEParaPortions +// ------------------------------------------------------------------------- +TEParaPortions::TEParaPortions() +{ +} + +TEParaPortions::~TEParaPortions() +{ + Reset(); +} + +void TEParaPortions::Reset() +{ + TEParaPortions::iterator aIter( begin() ); + while ( aIter != end() ) + delete *aIter++; + clear(); +} + +// ------------------------------------------------------------------------- +// (+) class IdleFormatter +// ------------------------------------------------------------------------- +IdleFormatter::IdleFormatter() +{ + mpView = 0; + mnRestarts = 0; +} + +IdleFormatter::~IdleFormatter() +{ + mpView = 0; +} + +void IdleFormatter::DoIdleFormat( TextView* pV, sal_uInt16 nMaxRestarts ) +{ + mpView = pV; + + if ( IsActive() ) + mnRestarts++; + + if ( mnRestarts > nMaxRestarts ) + { + mnRestarts = 0; + ((Link&)GetTimeoutHdl()).Call( this ); + } + else + { + Start(); + } +} + +void IdleFormatter::ForceTimeout() +{ + if ( IsActive() ) + { + Stop(); + mnRestarts = 0; + ((Link&)GetTimeoutHdl()).Call( this ); + } +} + +TYPEINIT1( TextHint, SfxSimpleHint ); + +TextHint::TextHint( sal_uLong Id ) : SfxSimpleHint( Id ) +{ + mnValue = 0; +} + +TextHint::TextHint( sal_uLong Id, sal_uLong nValue ) : SfxSimpleHint( Id ) +{ + mnValue = nValue; +} + +TEIMEInfos::TEIMEInfos( const TextPaM& rPos, const String& rOldTextAfterStartPos ) +: aOldTextAfterStartPos( rOldTextAfterStartPos ) +{ + aPos = rPos; + nLen = 0; + bCursor = sal_True; + pAttribs = NULL; + bWasCursorOverwrite = sal_False; +} + +TEIMEInfos::~TEIMEInfos() +{ + delete[] pAttribs; +} + +void TEIMEInfos::CopyAttribs( const sal_uInt16* pA, sal_uInt16 nL ) +{ + nLen = nL; + delete pAttribs; + pAttribs = new sal_uInt16[ nL ]; + memcpy( pAttribs, pA, nL*sizeof(sal_uInt16) ); +} + +void TEIMEInfos::DestroyAttribs() +{ + delete pAttribs; + pAttribs = NULL; + nLen = 0; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/edit/textdoc.cxx b/vcl/source/edit/textdoc.cxx new file mode 100644 index 0000000..a8062ec --- /dev/null +++ b/vcl/source/edit/textdoc.cxx @@ -0,0 +1,636 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include + +#include + + + +// Vergleichmethode wird von QuickSort gerufen... + +static bool CompareStart( const TextCharAttrib* pFirst, const TextCharAttrib* pSecond ) +{ + return pFirst->GetStart() < pSecond->GetStart(); +} + +// ------------------------------------------------------------------------- +// (+) class TextCharAttrib +// ------------------------------------------------------------------------- +TextCharAttrib::TextCharAttrib( const TextAttrib& rAttr, sal_uInt16 nStart, sal_uInt16 nEnd ) +{ + mpAttr = rAttr.Clone(); + mnStart = nStart, + mnEnd = nEnd; +} + +TextCharAttrib::TextCharAttrib( const TextCharAttrib& rTextCharAttrib ) +{ + mpAttr = rTextCharAttrib.GetAttr().Clone(); + mnStart = rTextCharAttrib.mnStart; + mnEnd = rTextCharAttrib.mnEnd; +} + +TextCharAttrib::~TextCharAttrib() +{ + delete mpAttr; +} + +// ------------------------------------------------------------------------- +// (+) class TextCharAttribList +// ------------------------------------------------------------------------- + +TextCharAttribList::TextCharAttribList() +{ + mbHasEmptyAttribs = sal_False; +} + +TextCharAttribList::~TextCharAttribList() +{ + // PTRARR_DEL +} + +void TextCharAttribList::Clear( sal_Bool bDestroyAttribs ) +{ + if ( bDestroyAttribs ) + for(iterator it = begin(); it != end(); ++it) + delete *it; + TextCharAttribs::clear(); +} + + +void TextCharAttribList::InsertAttrib( TextCharAttrib* pAttrib ) +{ + if ( pAttrib->IsEmpty() ) + mbHasEmptyAttribs = sal_True; + + const sal_uInt16 nCount = size(); + const sal_uInt16 nStart = pAttrib->GetStart(); // vielleicht besser fuer Comp.Opt. + sal_Bool bInserted = sal_False; + for ( sal_uInt16 x = 0; x < nCount; x++ ) + { + TextCharAttrib* pCurAttrib = GetAttrib( x ); + if ( pCurAttrib->GetStart() > nStart ) + { + insert( begin() + x, pAttrib ); + bInserted = sal_True; + break; + } + } + if ( !bInserted ) + push_back( pAttrib ); +} + +void TextCharAttribList::ResortAttribs() +{ + if ( !empty() ) + std::sort( begin(), end(), CompareStart ); +} + +TextCharAttrib* TextCharAttribList::FindAttrib( sal_uInt16 nWhich, sal_uInt16 nPos ) +{ + // Rueckwaerts, falls eins dort endet, das naechste startet. + // => Das startende gilt... + + for ( sal_uInt16 nAttr = size(); nAttr; ) + { + TextCharAttrib* pAttr = GetAttrib( --nAttr ); + + if ( pAttr->GetEnd() < nPos ) + return 0; + + if ( ( pAttr->Which() == nWhich ) && pAttr->IsIn(nPos) ) + return pAttr; + } + return NULL; +} + +TextCharAttrib* TextCharAttribList::FindNextAttrib( sal_uInt16 nWhich, sal_uInt16 nFromPos, sal_uInt16 nMaxPos ) const +{ + DBG_ASSERT( nWhich, "FindNextAttrib: Which?" ); + const sal_uInt16 nAttribs = size(); + for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ ) + { + TextCharAttrib* pAttr = GetAttrib( nAttr ); + if ( ( pAttr->GetStart() >= nFromPos ) && + ( pAttr->GetEnd() <= nMaxPos ) && + ( pAttr->Which() == nWhich ) ) + return pAttr; + } + return NULL; +} + +sal_Bool TextCharAttribList::HasAttrib( sal_uInt16 nWhich ) const +{ + for ( sal_uInt16 nAttr = size(); nAttr; ) + { + const TextCharAttrib* pAttr = GetAttrib( --nAttr ); + if ( pAttr->Which() == nWhich ) + return sal_True; + } + return sal_False; +} + +sal_Bool TextCharAttribList::HasBoundingAttrib( sal_uInt16 nBound ) +{ + // Rueckwaerts, falls eins dort endet, das naechste startet. + // => Das startende gilt... + for ( sal_uInt16 nAttr = size(); nAttr; ) + { + TextCharAttrib* pAttr = GetAttrib( --nAttr ); + + if ( pAttr->GetEnd() < nBound ) + return sal_False; + + if ( ( pAttr->GetStart() == nBound ) || ( pAttr->GetEnd() == nBound ) ) + return sal_True; + } + return sal_False; +} + +TextCharAttrib* TextCharAttribList::FindEmptyAttrib( sal_uInt16 nWhich, sal_uInt16 nPos ) +{ + if ( !mbHasEmptyAttribs ) + return 0; + + const sal_uInt16 nAttribs = size(); + for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ ) + { + TextCharAttrib* pAttr = GetAttrib( nAttr ); + if ( pAttr->GetStart() > nPos ) + return 0; + + if ( ( pAttr->GetStart() == nPos ) && ( pAttr->GetEnd() == nPos ) && ( pAttr->Which() == nWhich ) ) + return pAttr; + } + return 0; +} + +void TextCharAttribList::DeleteEmptyAttribs() +{ + for ( sal_uInt16 nAttr = 0; nAttr < size(); nAttr++ ) + { + TextCharAttrib* pAttr = GetAttrib( nAttr ); + if ( pAttr->IsEmpty() ) + { + erase( begin() + nAttr ); + delete pAttr; + nAttr--; + } + } + mbHasEmptyAttribs = sal_False; +} + +// ------------------------------------------------------------------------- +// (+) class TextNode +// ------------------------------------------------------------------------- + +TextNode::TextNode( const String& rText ) : + maText( rText ) +{ +} + +void TextNode::ExpandAttribs( sal_uInt16 nIndex, sal_uInt16 nNew ) +{ + if ( !nNew ) + return; + + sal_Bool bResort = sal_False; + sal_uInt16 nAttribs = maCharAttribs.Count(); + for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ ) + { + TextCharAttrib* pAttrib = maCharAttribs.GetAttrib( nAttr ); + if ( pAttrib->GetEnd() >= nIndex ) + { + // Alle Attribute hinter der Einfuegeposition verschieben... + if ( pAttrib->GetStart() > nIndex ) + { + pAttrib->MoveForward( nNew ); + } + // 0: Leeres Attribut expandieren, wenn an Einfuegestelle + else if ( pAttrib->IsEmpty() ) + { + // Index nicht pruefen, leeres durfte nur dort liegen. + // Wenn spaeter doch Ueberpruefung: + // Spezialfall: Start == 0; AbsLen == 1, nNew = 1 => Expand, weil durch Absatzumbruch! + // Start <= nIndex, End >= nIndex => Start=End=nIndex! +// if ( pAttrib->GetStart() == nIndex ) + pAttrib->Expand( nNew ); + } + // 1: Attribut startet davor, geht bis Index... + else if ( pAttrib->GetEnd() == nIndex ) // Start muss davor liegen + { + // Nur expandieren, wenn kein Feature, + // und wenn nicht in ExcludeListe! + // Sonst geht z.B. ein UL bis zum neuen ULDB, beide expandieren + if ( !maCharAttribs.FindEmptyAttrib( pAttrib->Which(), nIndex ) ) + { + pAttrib->Expand( nNew ); + } + else + bResort = sal_True; + } + // 2: Attribut startet davor, geht hinter Index... + else if ( ( pAttrib->GetStart() < nIndex ) && ( pAttrib->GetEnd() > nIndex ) ) + { + pAttrib->Expand( nNew ); + } + // 3: Attribut startet auf Index... + else if ( pAttrib->GetStart() == nIndex ) + { + if ( nIndex == 0 ) + { + pAttrib->Expand( nNew ); +// bResort = sal_True; // es gibt ja keine Features mehr... + } + else + pAttrib->MoveForward( nNew ); + } + } + + DBG_ASSERT( pAttrib->GetStart() <= pAttrib->GetEnd(), "Expand: Attribut verdreht!" ); + DBG_ASSERT( ( pAttrib->GetEnd() <= maText.Len() ), "Expand: Attrib groesser als Absatz!" ); + DBG_ASSERT( !pAttrib->IsEmpty(), "Leeres Attribut nach ExpandAttribs?" ); + } + + if ( bResort ) + maCharAttribs.ResortAttribs(); +} + +void TextNode::CollapsAttribs( sal_uInt16 nIndex, sal_uInt16 nDeleted ) +{ + if ( !nDeleted ) + return; + + sal_Bool bResort = sal_False; + sal_uInt16 nEndChanges = nIndex+nDeleted; + + for ( sal_uInt16 nAttr = 0; nAttr < maCharAttribs.Count(); nAttr++ ) + { + TextCharAttrib* pAttrib = maCharAttribs.GetAttrib( nAttr ); + sal_Bool bDelAttr = sal_False; + if ( pAttrib->GetEnd() >= nIndex ) + { + // Alles Attribute hinter der Einfuegeposition verschieben... + if ( pAttrib->GetStart() >= nEndChanges ) + { + pAttrib->MoveBackward( nDeleted ); + } + // 1. Innenliegende Attribute loeschen... + else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() <= nEndChanges ) ) + { + // Spezialfall: Attrubt deckt genau den Bereich ab + // => als leeres Attribut behalten. + if ( ( pAttrib->GetStart() == nIndex ) && ( pAttrib->GetEnd() == nEndChanges ) ) + pAttrib->GetEnd() = nIndex; // leer + else + bDelAttr = sal_True; + } + // 2. Attribut beginnt davor, endet drinnen oder dahinter... + else if ( ( pAttrib->GetStart() <= nIndex ) && ( pAttrib->GetEnd() > nIndex ) ) + { + if ( pAttrib->GetEnd() <= nEndChanges ) // endet drinnen + pAttrib->GetEnd() = nIndex; + else + pAttrib->Collaps( nDeleted ); // endet dahinter + } + // 3. Attribut beginnt drinnen, endet dahinter... + else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() > nEndChanges ) ) + { + // Features duerfen nicht expandieren! + pAttrib->GetStart() = nEndChanges; + pAttrib->MoveBackward( nDeleted ); + } + } + + DBG_ASSERT( pAttrib->GetStart() <= pAttrib->GetEnd(), "Collaps: Attribut verdreht!" ); + DBG_ASSERT( ( pAttrib->GetEnd() <= maText.Len()) || bDelAttr, "Collaps: Attrib groesser als Absatz!" ); + if ( bDelAttr /* || pAttrib->IsEmpty() */ ) + { + bResort = sal_True; + maCharAttribs.RemoveAttrib( nAttr ); + delete pAttrib; + nAttr--; + } + else if ( pAttrib->IsEmpty() ) + maCharAttribs.HasEmptyAttribs() = sal_True; + } + + if ( bResort ) + maCharAttribs.ResortAttribs(); +} + +void TextNode::InsertText( sal_uInt16 nPos, const String& rText ) +{ + maText.Insert( rText, nPos ); + ExpandAttribs( nPos, rText.Len() ); +} + +void TextNode::InsertText( sal_uInt16 nPos, sal_Unicode c ) +{ + maText.Insert( c, nPos ); + ExpandAttribs( nPos, 1 ); +} + +void TextNode::RemoveText( sal_uInt16 nPos, sal_uInt16 nChars ) +{ + maText.Erase( nPos, nChars ); + CollapsAttribs( nPos, nChars ); +} + +TextNode* TextNode::Split( sal_uInt16 nPos, sal_Bool bKeepEndingAttribs ) +{ + String aNewText; + if ( nPos < maText.Len() ) + { + aNewText = maText.Copy( nPos ); + maText.Erase( nPos ); + } + TextNode* pNew = new TextNode( aNewText ); + + for ( sal_uInt16 nAttr = 0; nAttr < maCharAttribs.Count(); nAttr++ ) + { + TextCharAttrib* pAttrib = maCharAttribs.GetAttrib( nAttr ); + if ( pAttrib->GetEnd() < nPos ) + { + // bleiben unveraendert.... + ; + } + else if ( pAttrib->GetEnd() == nPos ) + { + // muessen als leeres Attribut kopiert werden. + // !FindAttrib nur sinnvoll, wenn Rueckwaerts durch Liste! + if ( bKeepEndingAttribs && !pNew->maCharAttribs.FindAttrib( pAttrib->Which(), 0 ) ) + { + TextCharAttrib* pNewAttrib = new TextCharAttrib( *pAttrib ); + pNewAttrib->GetStart() = 0; + pNewAttrib->GetEnd() = 0; + pNew->maCharAttribs.InsertAttrib( pNewAttrib ); + } + } + else if ( pAttrib->IsInside( nPos ) || ( !nPos && !pAttrib->GetStart() ) ) + { + // Wenn ganz vorne gecuttet wird, muss das Attribut erhalten bleiben! + // muessen kopiert und geaendert werden + TextCharAttrib* pNewAttrib = new TextCharAttrib( *pAttrib ); + pNewAttrib->GetStart() = 0; + pNewAttrib->GetEnd() = pAttrib->GetEnd()-nPos; + pNew->maCharAttribs.InsertAttrib( pNewAttrib ); + // stutzen: + pAttrib->GetEnd() = nPos; + } + else + { + DBG_ASSERT( pAttrib->GetStart() >= nPos, "Start < nPos!" ); + DBG_ASSERT( pAttrib->GetEnd() >= nPos, "End < nPos!" ); + // alle dahinter verschieben in den neuen Node (this) + maCharAttribs.RemoveAttrib( nAttr ); + pNew->maCharAttribs.InsertAttrib( pAttrib ); + pAttrib->GetStart() = pAttrib->GetStart() - nPos; + pAttrib->GetEnd() = pAttrib->GetEnd() - nPos; + nAttr--; + } + } + return pNew; +} + +void TextNode::Append( const TextNode& rNode ) +{ + sal_uInt16 nOldLen = maText.Len(); + + maText += rNode.GetText(); + + const sal_uInt16 nAttribs = rNode.GetCharAttribs().Count(); + for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ ) + { + TextCharAttrib* pAttrib = rNode.GetCharAttribs().GetAttrib( nAttr ); + sal_Bool bMelted = sal_False; + if ( pAttrib->GetStart() == 0 ) + { + // Evtl koennen Attribute zusammengefasst werden: + sal_uInt16 nTmpAttribs = maCharAttribs.Count(); + for ( sal_uInt16 nTmpAttr = 0; nTmpAttr < nTmpAttribs; nTmpAttr++ ) + { + TextCharAttrib* pTmpAttrib = maCharAttribs.GetAttrib( nTmpAttr ); + + if ( pTmpAttrib->GetEnd() == nOldLen ) + { + if ( ( pTmpAttrib->Which() == pAttrib->Which() ) && + ( pTmpAttrib->GetAttr() == pAttrib->GetAttr() ) ) + { + pTmpAttrib->GetEnd() = + pTmpAttrib->GetEnd() + pAttrib->GetLen(); + bMelted = sal_True; + break; // es kann nur eins von der Sorte an der Stelle geben + } + } + } + } + + if ( !bMelted ) + { + TextCharAttrib* pNewAttrib = new TextCharAttrib( *pAttrib ); + pNewAttrib->GetStart() = pNewAttrib->GetStart() + nOldLen; + pNewAttrib->GetEnd() = pNewAttrib->GetEnd() + nOldLen; + maCharAttribs.InsertAttrib( pNewAttrib ); + } + } +} + +// ------------------------------------------------------------------------- +// (+) class TextDoc +// ------------------------------------------------------------------------- + +TextDoc::TextDoc() +{ + mnLeftMargin = 0; +}; + +TextDoc::~TextDoc() +{ + DestroyTextNodes(); +} + +void TextDoc::Clear() +{ + DestroyTextNodes(); +} + +void TextDoc::DestroyTextNodes() +{ + for ( sal_uLong nNode = 0; nNode < maTextNodes.Count(); nNode++ ) + delete maTextNodes.GetObject( nNode ); + maTextNodes.clear(); +} + +String TextDoc::GetText( const sal_Unicode* pSep ) const +{ + sal_uLong nLen = GetTextLen( pSep ); + sal_uLong nNodes = maTextNodes.Count(); + + if ( nLen > STRING_MAXLEN ) + { + OSL_FAIL( "Text zu gross fuer String" ); + return String(); + } + + String aASCIIText; + sal_uLong nLastNode = nNodes-1; + for ( sal_uLong nNode = 0; nNode < nNodes; nNode++ ) + { + TextNode* pNode = maTextNodes.GetObject( nNode ); + String aTmp( pNode->GetText() ); + aASCIIText += aTmp; + if ( pSep && ( nNode != nLastNode ) ) + aASCIIText += pSep; + } + + return aASCIIText; +} + +XubString TextDoc::GetText( sal_uLong nPara ) const +{ + XubString aText; + TextNode* pNode = ( nPara < maTextNodes.Count() ) ? maTextNodes.GetObject( nPara ) : 0; + if ( pNode ) + aText = pNode->GetText(); + + return aText; +} + + +sal_uLong TextDoc::GetTextLen( const xub_Unicode* pSep, const TextSelection* pSel ) const +{ + sal_uLong nLen = 0; + sal_uLong nNodes = maTextNodes.Count(); + if ( nNodes ) + { + sal_uLong nStartNode = 0; + sal_uLong nEndNode = nNodes-1; + if ( pSel ) + { + nStartNode = pSel->GetStart().GetPara(); + nEndNode = pSel->GetEnd().GetPara(); + } + + for ( sal_uLong nNode = nStartNode; nNode <= nEndNode; nNode++ ) + { + TextNode* pNode = maTextNodes.GetObject( nNode ); + + sal_uInt16 nS = 0; + sal_uLong nE = pNode->GetText().Len(); + if ( pSel && ( nNode == pSel->GetStart().GetPara() ) ) + nS = pSel->GetStart().GetIndex(); + if ( pSel && ( nNode == pSel->GetEnd().GetPara() ) ) + nE = pSel->GetEnd().GetIndex(); + + nLen += ( nE - nS ); + } + + if ( pSep ) + nLen += (nEndNode-nStartNode) * rtl_ustr_getLength(pSep); + } + + return nLen; +} + +TextPaM TextDoc::InsertText( const TextPaM& rPaM, xub_Unicode c ) +{ + DBG_ASSERT( c != 0x0A, "TextDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" ); + DBG_ASSERT( c != 0x0D, "TextDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" ); + + TextNode* pNode = maTextNodes.GetObject( rPaM.GetPara() ); + pNode->InsertText( rPaM.GetIndex(), c ); + + TextPaM aPaM( rPaM.GetPara(), rPaM.GetIndex()+1 ); + return aPaM; +} + +TextPaM TextDoc::InsertText( const TextPaM& rPaM, const XubString& rStr ) +{ + DBG_ASSERT( rStr.Search( 0x0A ) == STRING_NOTFOUND, "TextDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" ); + DBG_ASSERT( rStr.Search( 0x0D ) == STRING_NOTFOUND, "TextDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" ); + + TextNode* pNode = maTextNodes.GetObject( rPaM.GetPara() ); + pNode->InsertText( rPaM.GetIndex(), rStr ); + + TextPaM aPaM( rPaM.GetPara(), rPaM.GetIndex()+rStr.Len() ); + return aPaM; +} + +TextPaM TextDoc::InsertParaBreak( const TextPaM& rPaM, sal_Bool bKeepEndingAttribs ) +{ + TextNode* pNode = maTextNodes.GetObject( rPaM.GetPara() ); + TextNode* pNew = pNode->Split( rPaM.GetIndex(), bKeepEndingAttribs ); + + maTextNodes.Insert( pNew, rPaM.GetPara()+1 ); + + TextPaM aPaM( rPaM.GetPara()+1, 0 ); + return aPaM; +} + +TextPaM TextDoc::ConnectParagraphs( TextNode* pLeft, TextNode* pRight ) +{ + sal_uInt16 nPrevLen = pLeft->GetText().Len(); + pLeft->Append( *pRight ); + + // der rechte verschwindet. + sal_uLong nRight = maTextNodes.GetPos( pRight ); + maTextNodes.Remove( nRight ); + delete pRight; + + sal_uLong nLeft = maTextNodes.GetPos( pLeft ); + TextPaM aPaM( nLeft, nPrevLen ); + return aPaM; +} + +TextPaM TextDoc::RemoveChars( const TextPaM& rPaM, sal_uInt16 nChars ) +{ + TextNode* pNode = maTextNodes.GetObject( rPaM.GetPara() ); + pNode->RemoveText( rPaM.GetIndex(), nChars ); + + return rPaM; +} + +sal_Bool TextDoc::IsValidPaM( const TextPaM& rPaM ) +{ + if ( rPaM.GetPara() >= maTextNodes.Count() ) + { + OSL_FAIL( "PaM: Para out of range" ); + return sal_False; + } + TextNode * pNode = maTextNodes.GetObject( rPaM.GetPara() ); + if ( rPaM.GetIndex() > pNode->GetText().Len() ) + { + OSL_FAIL( "PaM: Index out of range" ); + return sal_False; + } + return sal_True; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/edit/textdoc.hxx b/vcl/source/edit/textdoc.hxx new file mode 100644 index 0000000..a1529a4 --- /dev/null +++ b/vcl/source/edit/textdoc.hxx @@ -0,0 +1,145 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _TEXTDOC_HXX +#define _TEXTDOC_HXX + +#include +#include + +#include +#include + +class TextCharAttribs : public std::vector { +public: + ~TextCharAttribs() + { + for( iterator it = begin(); it != end(); ++it ) + delete *it; + } +}; + +class TextCharAttribList : private TextCharAttribs +{ +private: + sal_Bool mbHasEmptyAttribs; + + TextCharAttribList( const TextCharAttribList& ) : TextCharAttribs() {} + +public: + TextCharAttribList(); + ~TextCharAttribList(); + + void Clear( sal_Bool bDestroyAttribs ); + sal_uInt16 Count() const { return TextCharAttribs::size(); } + + TextCharAttrib* GetAttrib( sal_uInt16 n ) const { return TextCharAttribs::operator[]( n ); } + void RemoveAttrib( sal_uInt16 n ) { TextCharAttribs::erase( begin() + n ); } + + void InsertAttrib( TextCharAttrib* pAttrib ); + + void DeleteEmptyAttribs(); + void ResortAttribs(); + + sal_Bool HasEmptyAttribs() const { return mbHasEmptyAttribs; } + sal_Bool& HasEmptyAttribs() { return mbHasEmptyAttribs; } + + TextCharAttrib* FindAttrib( sal_uInt16 nWhich, sal_uInt16 nPos ); + TextCharAttrib* FindNextAttrib( sal_uInt16 nWhich, sal_uInt16 nFromPos, sal_uInt16 nMaxPos = 0xFFFF ) const; + TextCharAttrib* FindEmptyAttrib( sal_uInt16 nWhich, sal_uInt16 nPos ); + sal_Bool HasAttrib( sal_uInt16 nWhich ) const; + sal_Bool HasBoundingAttrib( sal_uInt16 nBound ); +}; + + +class TextNode +{ +private: + String maText; + TextCharAttribList maCharAttribs; + + TextNode( const TextNode& ) {;} +protected: + void ExpandAttribs( sal_uInt16 nIndex, sal_uInt16 nNewChars ); + void CollapsAttribs( sal_uInt16 nIndex, sal_uInt16 nDelChars ); + +public: + TextNode( const String& rText ); + + + const String& GetText() const { return maText; } + + const TextCharAttribList& GetCharAttribs() const { return maCharAttribs; } + TextCharAttribList& GetCharAttribs() { return maCharAttribs; } + + void InsertText( sal_uInt16 nPos, const String& rText ); + void InsertText( sal_uInt16 nPos, sal_Unicode c ); + void RemoveText( sal_uInt16 nPos, sal_uInt16 nChars ); + + TextNode* Split( sal_uInt16 nPos, sal_Bool bKeepEndigAttribs ); + void Append( const TextNode& rNode ); +}; + +class TextDoc +{ +private: + ToolsList maTextNodes; + sal_uInt16 mnLeftMargin; + +protected: + void DestroyTextNodes(); + +public: + TextDoc(); + ~TextDoc(); + + void Clear(); + + ToolsList& GetNodes() { return maTextNodes; } + const ToolsList& GetNodes() const { return maTextNodes; } + + TextPaM RemoveChars( const TextPaM& rPaM, sal_uInt16 nChars ); + TextPaM InsertText( const TextPaM& rPaM, sal_Unicode c ); + TextPaM InsertText( const TextPaM& rPaM, const String& rStr ); + + TextPaM InsertParaBreak( const TextPaM& rPaM, sal_Bool bKeepEndingAttribs ); + TextPaM ConnectParagraphs( TextNode* pLeft, TextNode* pRight ); + + sal_uLong GetTextLen( const sal_Unicode* pSep, const TextSelection* pSel = NULL ) const; + String GetText( const sal_Unicode* pSep ) const; + String GetText( sal_uLong nPara ) const; + + void SetLeftMargin( sal_uInt16 n ) { mnLeftMargin = n; } + sal_uInt16 GetLeftMargin() const { return mnLeftMargin; } + + sal_Bool IsValidPaM( const TextPaM& rPaM ); +}; + +#endif // _TEXTDOC_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/edit/texteng.cxx b/vcl/source/edit/texteng.cxx new file mode 100644 index 0000000..bd6d179 --- /dev/null +++ b/vcl/source/edit/texteng.cxx @@ -0,0 +1,3205 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#include + +#include +#include +#include + +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::rtl; + + +// ------------------------------------------------------------------------- +// (-) class TextEngine +// ------------------------------------------------------------------------- +TextEngine::TextEngine() +{ + mpDoc = 0; + mpTEParaPortions = 0; + + mpViews = new TextViews; + mpActiveView = NULL; + + mbIsFormatting = sal_False; + mbFormatted = sal_False; + mbUpdate = sal_True; + mbModified = sal_False; + mbUndoEnabled = sal_False; + mbIsInUndo = sal_False; + mbDowning = sal_False; + mbRightToLeft = sal_False; + mbHasMultiLineParas = sal_False; + + meAlign = TXTALIGN_LEFT; + + mnMaxTextWidth = 0; + mnMaxTextLen = 0; + mnCurTextWidth = 0xFFFFFFFF; + mnCurTextHeight = 0; + + mpUndoManager = NULL; + mpIMEInfos = NULL; + mpLocaleDataWrapper = NULL; + + mpIdleFormatter = new IdleFormatter; + mpIdleFormatter->SetTimeoutHdl( LINK( this, TextEngine, IdleFormatHdl ) ); + + mpRefDev = new VirtualDevice; + + ImpInitLayoutMode( mpRefDev ); + + ImpInitDoc(); + + maTextColor = COL_BLACK; + Font aFont; + aFont.SetTransparent( sal_False ); + Color aFillColor( aFont.GetFillColor() ); + aFillColor.SetTransparency( 0 ); + aFont.SetFillColor( aFillColor ); + SetFont( aFont ); +} + +TextEngine::~TextEngine() +{ + mbDowning = sal_True; + + delete mpIdleFormatter; + delete mpDoc; + delete mpTEParaPortions; + delete mpViews; // nur die Liste, nicht die Vies + delete mpRefDev; + delete mpUndoManager; + delete mpIMEInfos; + delete mpLocaleDataWrapper; +} + +void TextEngine::InsertView( TextView* pTextView ) +{ + mpViews->push_back( pTextView ); + pTextView->SetSelection( TextSelection() ); + + if ( !GetActiveView() ) + SetActiveView( pTextView ); +} + +void TextEngine::RemoveView( TextView* pTextView ) +{ + TextViews::iterator it = std::find( mpViews->begin(), mpViews->end(), pTextView ); + if( it != mpViews->end() ) + { + pTextView->HideCursor(); + mpViews->erase( it ); + if ( pTextView == GetActiveView() ) + SetActiveView( 0 ); + } +} + +sal_uInt16 TextEngine::GetViewCount() const +{ + return mpViews->size(); +} + +TextView* TextEngine::GetView( sal_uInt16 nView ) const +{ + return (*mpViews)[ nView ]; +} + +TextView* TextEngine::GetActiveView() const +{ + return mpActiveView; +} + +void TextEngine::SetActiveView( TextView* pTextView ) +{ + if ( pTextView != mpActiveView ) + { + if ( mpActiveView ) + mpActiveView->HideSelection(); + + mpActiveView = pTextView; + + if ( mpActiveView ) + mpActiveView->ShowSelection(); + } +} + +void TextEngine::SetFont( const Font& rFont ) +{ + if ( rFont != maFont ) + { + maFont = rFont; + // #i40221# As the font's color now defaults to transparent (since i35764) + // we have to choose a useful textcolor in this case. + // Otherwise maTextColor and maFont.GetColor() are both transparent.... + if( rFont.GetColor() == COL_TRANSPARENT ) + maTextColor = COL_BLACK; + else + maTextColor = rFont.GetColor(); + + // Wegen Selektion keinen Transparenten Font zulassen... + // (Sonst spaeter in ImplPaint den Hintergrund anders loeschen...) + maFont.SetTransparent( sal_False ); + // Tell VCL not to use the font color, use text color from OutputDevice + maFont.SetColor( COL_TRANSPARENT ); + Color aFillColor( maFont.GetFillColor() ); + aFillColor.SetTransparency( 0 ); + maFont.SetFillColor( aFillColor ); + + maFont.SetAlign( ALIGN_TOP ); + mpRefDev->SetFont( maFont); + Size aTextSize; + aTextSize.Width() = mpRefDev->GetTextWidth(rtl::OUString(" ")); + aTextSize.Height() = mpRefDev->GetTextHeight(); + if ( !aTextSize.Width() ) + aTextSize.Width() = mpRefDev->GetTextWidth(rtl::OUString("XXXX")); + + mnDefTab = (sal_uInt16)aTextSize.Width(); + if ( !mnDefTab ) + mnDefTab = 1; + mnCharHeight = (sal_uInt16)aTextSize.Height(); + mnFixCharWidth100 = 0; + + FormatFullDoc(); + UpdateViews(); + + for ( sal_uInt16 nView = mpViews->size(); nView; ) + { + TextView* pView = (*mpViews)[ --nView ]; + pView->GetWindow()->SetInputContext( InputContext( GetFont(), !pView->IsReadOnly() ? INPUTCONTEXT_TEXT|INPUTCONTEXT_EXTTEXTINPUT : 0 ) ); + } + } +} + +void TextEngine::SetMaxTextLen( sal_uLong nLen ) +{ + mnMaxTextLen = nLen; +} + +void TextEngine::SetMaxTextWidth( sal_uLong nMaxWidth ) +{ + if ( nMaxWidth != mnMaxTextWidth ) + { + mnMaxTextWidth = Min( nMaxWidth, (sal_uLong)0x7FFFFFFF ); + FormatFullDoc(); + UpdateViews(); + } +} + +static sal_Unicode static_aLFText[] = { '\n', 0 }; +static sal_Unicode static_aCRText[] = { '\r', 0 }; +static sal_Unicode static_aCRLFText[] = { '\r', '\n', 0 }; + +static inline const sal_Unicode* static_getLineEndText( LineEnd aLineEnd ) +{ + const sal_Unicode* pRet = NULL; + + switch( aLineEnd ) + { + case LINEEND_LF: pRet = static_aLFText;break; + case LINEEND_CR: pRet = static_aCRText;break; + case LINEEND_CRLF: pRet = static_aCRLFText;break; + } + return pRet; +} + +void TextEngine::ReplaceText(const TextSelection& rSel, const String& rText) +{ + ImpInsertText( rSel, rText ); +} + +String TextEngine::GetText( LineEnd aSeparator ) const +{ + return mpDoc->GetText( static_getLineEndText( aSeparator ) ); +} + +String TextEngine::GetTextLines( LineEnd aSeparator ) const +{ + String aText; + sal_uLong nParas = mpTEParaPortions->Count(); + const sal_Unicode* pSep = static_getLineEndText( aSeparator ); + for ( sal_uLong nP = 0; nP < nParas; nP++ ) + { + TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nP ); + + sal_uInt16 nLines = pTEParaPortion->GetLines().size(); + for ( sal_uInt16 nL = 0; nL < nLines; nL++ ) + { + TextLine* pLine = pTEParaPortion->GetLines()[nL]; + aText += pTEParaPortion->GetNode()->GetText().Copy( pLine->GetStart(), pLine->GetEnd() - pLine->GetStart() ); + if ( pSep && ( ( (nP+1) < nParas ) || ( (nL+1) < nLines ) ) ) + aText += pSep; + } + } + return aText; +} + +String TextEngine::GetText( sal_uLong nPara ) const +{ + return mpDoc->GetText( nPara ); +} + +sal_uLong TextEngine::GetTextLen( LineEnd aSeparator ) const +{ + return mpDoc->GetTextLen( static_getLineEndText( aSeparator ) ); +} + +sal_uLong TextEngine::GetTextLen( const TextSelection& rSel, LineEnd aSeparator ) const +{ + TextSelection aSel( rSel ); + aSel.Justify(); + ValidateSelection( aSel ); + return mpDoc->GetTextLen( static_getLineEndText( aSeparator ), &aSel ); +} + +sal_uInt16 TextEngine::GetTextLen( sal_uLong nPara ) const +{ + return mpDoc->GetNodes().GetObject( nPara )->GetText().Len(); +} + +void TextEngine::SetUpdateMode( sal_Bool bUpdate ) +{ + if ( bUpdate != mbUpdate ) + { + mbUpdate = bUpdate; + if ( mbUpdate ) + { + FormatAndUpdate( GetActiveView() ); + if ( GetActiveView() ) + GetActiveView()->ShowCursor(); + } + } +} + +sal_Bool TextEngine::DoesKeyChangeText( const KeyEvent& rKeyEvent ) +{ + sal_Bool bDoesChange = sal_False; + + KeyFuncType eFunc = rKeyEvent.GetKeyCode().GetFunction(); + if ( eFunc != KEYFUNC_DONTKNOW ) + { + switch ( eFunc ) + { + case KEYFUNC_UNDO: + case KEYFUNC_REDO: + case KEYFUNC_CUT: + case KEYFUNC_PASTE: bDoesChange = sal_True; + break; + default: // wird dann evtl. unten bearbeitet. + eFunc = KEYFUNC_DONTKNOW; + } + } + if ( eFunc == KEYFUNC_DONTKNOW ) + { + switch ( rKeyEvent.GetKeyCode().GetCode() ) + { + case KEY_DELETE: + case KEY_BACKSPACE: + { + if ( !rKeyEvent.GetKeyCode().IsMod2() ) + bDoesChange = sal_True; + } + break; + case KEY_RETURN: + case KEY_TAB: + { + if ( !rKeyEvent.GetKeyCode().IsMod1() && !rKeyEvent.GetKeyCode().IsMod2() ) + bDoesChange = sal_True; + } + break; + default: + { + bDoesChange = TextEngine::IsSimpleCharInput( rKeyEvent ); + } + } + } + return bDoesChange; +} + +sal_Bool TextEngine::IsSimpleCharInput( const KeyEvent& rKeyEvent ) +{ + if( rKeyEvent.GetCharCode() >= 32 && rKeyEvent.GetCharCode() != 127 && + KEY_MOD1 != (rKeyEvent.GetKeyCode().GetModifier() & ~KEY_SHIFT) && // (ssa) #i45714#: + KEY_MOD2 != (rKeyEvent.GetKeyCode().GetModifier() & ~KEY_SHIFT) ) // check for Ctrl and Alt separately + { + return sal_True; + } + return sal_False; +} + +void TextEngine::ImpInitDoc() +{ + if ( mpDoc ) + mpDoc->Clear(); + else + mpDoc = new TextDoc; + + delete mpTEParaPortions; + mpTEParaPortions = new TEParaPortions; + + TextNode* pNode = new TextNode( String() ); + mpDoc->GetNodes().Insert( pNode, 0 ); + + TEParaPortion* pIniPortion = new TEParaPortion( pNode ); + mpTEParaPortions->Insert( pIniPortion, (sal_uLong)0 ); + + mbFormatted = sal_False; + + ImpParagraphRemoved( TEXT_PARA_ALL ); + ImpParagraphInserted( 0 ); +} + +String TextEngine::GetText( const TextSelection& rSel, LineEnd aSeparator ) const +{ + String aText; + + if ( !rSel.HasRange() ) + return aText; + + TextSelection aSel( rSel ); + aSel.Justify(); + + sal_uLong nStartPara = aSel.GetStart().GetPara(); + sal_uLong nEndPara = aSel.GetEnd().GetPara(); + const sal_Unicode* pSep = static_getLineEndText( aSeparator ); + for ( sal_uLong nNode = aSel.GetStart().GetPara(); nNode <= nEndPara; nNode++ ) + { + TextNode* pNode = mpDoc->GetNodes().GetObject( nNode ); + + sal_uInt16 nStartPos = 0; + sal_uInt16 nEndPos = pNode->GetText().Len(); + if ( nNode == nStartPara ) + nStartPos = aSel.GetStart().GetIndex(); + if ( nNode == nEndPara ) // kann auch == nStart sein! + nEndPos = aSel.GetEnd().GetIndex(); + + aText += pNode->GetText().Copy( nStartPos, nEndPos-nStartPos ); + if ( nNode < nEndPara ) + aText += pSep; + } + return aText; +} + +void TextEngine::ImpRemoveText() +{ + ImpInitDoc(); + + TextPaM aStartPaM( 0, 0 ); + TextSelection aEmptySel( aStartPaM, aStartPaM ); + for ( sal_uInt16 nView = 0; nView < mpViews->size(); nView++ ) + { + TextView* pView = (*mpViews)[ nView ]; + pView->ImpSetSelection( aEmptySel ); + } + ResetUndo(); +} + +void TextEngine::SetText( const XubString& rText ) +{ + ImpRemoveText(); + + sal_Bool bUndoCurrentlyEnabled = IsUndoEnabled(); + // Der von Hand reingesteckte Text kann nicht vom Anwender rueckgaengig gemacht werden. + EnableUndo( sal_False ); + + TextPaM aStartPaM( 0, 0 ); + TextSelection aEmptySel( aStartPaM, aStartPaM ); + + TextPaM aPaM = aStartPaM; + if ( rText.Len() ) + aPaM = ImpInsertText( aEmptySel, rText ); + + for ( sal_uInt16 nView = 0; nView < mpViews->size(); nView++ ) + { + TextView* pView = (*mpViews)[ nView ]; + pView->ImpSetSelection( aEmptySel ); + + // Wenn kein Text, dann auch Kein Format&Update + // => Der Text bleibt stehen. + if ( !rText.Len() && GetUpdateMode() ) + pView->Invalidate(); + } + + if( !rText.Len() ) // sonst muss spaeter noch invalidiert werden, !bFormatted reicht. + mnCurTextHeight = 0; + + FormatAndUpdate(); + + EnableUndo( bUndoCurrentlyEnabled ); + DBG_ASSERT( !HasUndoManager() || !GetUndoManager().GetUndoActionCount(), "Undo nach SetText?" ); +} + + +void TextEngine::CursorMoved( sal_uLong nNode ) +{ + // Leere Attribute loeschen, aber nur, wenn Absatz nicht leer! + TextNode* pNode = mpDoc->GetNodes().GetObject( nNode ); + if ( pNode && pNode->GetCharAttribs().HasEmptyAttribs() && pNode->GetText().Len() ) + pNode->GetCharAttribs().DeleteEmptyAttribs(); +} + +void TextEngine::ImpRemoveChars( const TextPaM& rPaM, sal_uInt16 nChars, SfxUndoAction* ) +{ + DBG_ASSERT( nChars, "ImpRemoveChars - 0 Chars?!" ); + if ( IsUndoEnabled() && !IsInUndo() ) + { + // Attribute muessen hier vorm RemoveChars fuer UNDO gesichert werden! + TextNode* pNode = mpDoc->GetNodes().GetObject( rPaM.GetPara() ); + XubString aStr( pNode->GetText().Copy( rPaM.GetIndex(), nChars ) ); + + // Pruefen, ob Attribute geloescht oder geaendert werden: + sal_uInt16 nStart = rPaM.GetIndex(); + sal_uInt16 nEnd = nStart + nChars; + for ( sal_uInt16 nAttr = pNode->GetCharAttribs().Count(); nAttr; ) + { + TextCharAttrib* pAttr = pNode->GetCharAttribs().GetAttrib( --nAttr ); + if ( ( pAttr->GetEnd() >= nStart ) && ( pAttr->GetStart() < nEnd ) ) + { + break; // for + } + } + InsertUndo( new TextUndoRemoveChars( this, rPaM, aStr ) ); + } + + mpDoc->RemoveChars( rPaM, nChars ); + ImpCharsRemoved( rPaM.GetPara(), rPaM.GetIndex(), nChars ); +} + +TextPaM TextEngine::ImpConnectParagraphs( sal_uLong nLeft, sal_uLong nRight ) +{ + DBG_ASSERT( nLeft != nRight, "Den gleichen Absatz zusammenfuegen ?" ); + + TextNode* pLeft = mpDoc->GetNodes().GetObject( nLeft ); + TextNode* pRight = mpDoc->GetNodes().GetObject( nRight ); + + if ( IsUndoEnabled() && !IsInUndo() ) + InsertUndo( new TextUndoConnectParas( this, nLeft, pLeft->GetText().Len() ) ); + + // Erstmal Portions suchen, da pRight nach ConnectParagraphs weg. + TEParaPortion* pLeftPortion = mpTEParaPortions->GetObject( nLeft ); + TEParaPortion* pRightPortion = mpTEParaPortions->GetObject( nRight ); + DBG_ASSERT( pLeft && pLeftPortion, "Blinde Portion in ImpConnectParagraphs(1)" ); + DBG_ASSERT( pRight && pRightPortion, "Blinde Portion in ImpConnectParagraphs(2)" ); + + TextPaM aPaM = mpDoc->ConnectParagraphs( pLeft, pRight ); + ImpParagraphRemoved( nRight ); + + pLeftPortion->MarkSelectionInvalid( aPaM.GetIndex(), pLeft->GetText().Len() ); + + mpTEParaPortions->Remove( nRight ); + delete pRightPortion; + // der rechte Node wird von EditDoc::ConnectParagraphs() geloescht. + + return aPaM; +} + +TextPaM TextEngine::ImpDeleteText( const TextSelection& rSel ) +{ + if ( !rSel.HasRange() ) + return rSel.GetStart(); + + TextSelection aSel( rSel ); + aSel.Justify(); + TextPaM aStartPaM( aSel.GetStart() ); + TextPaM aEndPaM( aSel.GetEnd() ); + + CursorMoved( aStartPaM.GetPara() ); // nur damit neu eingestellte Attribute verschwinden... + CursorMoved( aEndPaM.GetPara() ); // nur damit neu eingestellte Attribute verschwinden... + + DBG_ASSERT( mpDoc->IsValidPaM( aStartPaM ), "Index im Wald in ImpDeleteText" ); + DBG_ASSERT( mpDoc->IsValidPaM( aEndPaM ), "Index im Wald in ImpDeleteText" ); + + sal_uLong nStartNode = aStartPaM.GetPara(); + sal_uLong nEndNode = aEndPaM.GetPara(); + + // Alle Nodes dazwischen entfernen.... + for ( sal_uLong z = nStartNode+1; z < nEndNode; z++ ) + { + // Immer nStartNode+1, wegen Remove()! + ImpRemoveParagraph( nStartNode+1 ); + } + + if ( nStartNode != nEndNode ) + { + // Den Rest des StartNodes... + TextNode* pLeft = mpDoc->GetNodes().GetObject( nStartNode ); + sal_uInt16 nChars = pLeft->GetText().Len() - aStartPaM.GetIndex(); + if ( nChars ) + { + ImpRemoveChars( aStartPaM, nChars ); + TEParaPortion* pPortion = mpTEParaPortions->GetObject( nStartNode ); + DBG_ASSERT( pPortion, "Blinde Portion in ImpDeleteText(3)" ); + pPortion->MarkSelectionInvalid( aStartPaM.GetIndex(), pLeft->GetText().Len() ); + } + + // Den Anfang des EndNodes.... + nEndNode = nStartNode+1; // Die anderen Absaetze wurden geloescht + nChars = aEndPaM.GetIndex(); + if ( nChars ) + { + aEndPaM.GetPara() = nEndNode; + aEndPaM.GetIndex() = 0; + ImpRemoveChars( aEndPaM, nChars ); + TEParaPortion* pPortion = mpTEParaPortions->GetObject( nEndNode ); + DBG_ASSERT( pPortion, "Blinde Portion in ImpDeleteText(4)" ); + pPortion->MarkSelectionInvalid( 0, pPortion->GetNode()->GetText().Len() ); + } + + // Zusammenfuegen.... + aStartPaM = ImpConnectParagraphs( nStartNode, nEndNode ); + } + else + { + sal_uInt16 nChars; + nChars = aEndPaM.GetIndex() - aStartPaM.GetIndex(); + ImpRemoveChars( aStartPaM, nChars ); + TEParaPortion* pPortion = mpTEParaPortions->GetObject( nStartNode ); + DBG_ASSERT( pPortion, "Blinde Portion in ImpDeleteText(5)" ); + pPortion->MarkInvalid( aEndPaM.GetIndex(), aStartPaM.GetIndex() - aEndPaM.GetIndex() ); + } + +// UpdateSelections(); + TextModified(); + return aStartPaM; +} + +void TextEngine::ImpRemoveParagraph( sal_uLong nPara ) +{ + TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); + TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPara ); + + // Der Node wird vom Undo verwaltet und ggf. zerstoert! + /* delete */ mpDoc->GetNodes().Remove( nPara ); + if ( IsUndoEnabled() && !IsInUndo() ) + InsertUndo( new TextUndoDelPara( this, pNode, nPara ) ); + else + delete pNode; + + mpTEParaPortions->Remove( nPara ); + delete pPortion; + + ImpParagraphRemoved( nPara ); +} + +uno::Reference < i18n::XExtendedInputSequenceChecker > TextEngine::GetInputSequenceChecker() const +{ + uno::Reference < i18n::XExtendedInputSequenceChecker > xISC; +// if ( !xISC.is() ) + { + uno::Reference< lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory(); + uno::Reference< uno::XInterface > xI = xMSF->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.i18n.InputSequenceChecker" )) ); + if ( xI.is() ) + { + Any x = xI->queryInterface( ::getCppuType((const uno::Reference< i18n::XExtendedInputSequenceChecker >*)0) ); + x >>= xISC; + } + } + return xISC; +} + +sal_Bool TextEngine::IsInputSequenceCheckingRequired( sal_Unicode c, const TextSelection& rCurSel ) const +{ + uno::Reference< i18n::XBreakIterator > xBI = ((TextEngine *) this)->GetBreakIterator(); + SvtCTLOptions aCTLOptions; + + // get the index that really is first + sal_uInt16 nFirstPos = rCurSel.GetStart().GetIndex(); + sal_uInt16 nMaxPos = rCurSel.GetEnd().GetIndex(); + if (nMaxPos < nFirstPos) + nFirstPos = nMaxPos; + + sal_Bool bIsSequenceChecking = + aCTLOptions.IsCTLFontEnabled() && + aCTLOptions.IsCTLSequenceChecking() && + nFirstPos != 0 && /* first char needs not to be checked */ + xBI.is() && i18n::ScriptType::COMPLEX == xBI->getScriptType( rtl::OUString( c ), 0 ); + + return bIsSequenceChecking; +} + +TextPaM TextEngine::ImpInsertText( const TextSelection& rCurSel, sal_Unicode c, sal_Bool bOverwrite ) +{ + return ImpInsertText( c, rCurSel, bOverwrite, sal_False ); +} + +TextPaM TextEngine::ImpInsertText( sal_Unicode c, const TextSelection& rCurSel, sal_Bool bOverwrite, sal_Bool bIsUserInput ) +{ + DBG_ASSERT( c != '\n', "Zeilenumbruch bei InsertText ?" ); + DBG_ASSERT( c != '\r', "Zeilenumbruch bei InsertText ?" ); + + TextPaM aPaM( rCurSel.GetStart() ); + TextNode* pNode = mpDoc->GetNodes().GetObject( aPaM.GetPara() ); + + if ( pNode->GetText().Len() < STRING_MAXLEN ) + { + sal_Bool bDoOverwrite = ( bOverwrite && + ( aPaM.GetIndex() < pNode->GetText().Len() ) ) ? sal_True : sal_False; + + sal_Bool bUndoAction = ( rCurSel.HasRange() || bDoOverwrite ); + + if ( bUndoAction ) + UndoActionStart(); + + if ( rCurSel.HasRange() ) + { + aPaM = ImpDeleteText( rCurSel ); + } + else if ( bDoOverwrite ) + { + // Wenn Selektion, dann kein Zeichen ueberschreiben + TextSelection aTmpSel( aPaM ); + aTmpSel.GetEnd().GetIndex()++; + ImpDeleteText( aTmpSel ); + } + + if (bIsUserInput && IsInputSequenceCheckingRequired( c, rCurSel )) + { + uno::Reference < i18n::XExtendedInputSequenceChecker > xISC = GetInputSequenceChecker(); + SvtCTLOptions aCTLOptions; + + if (xISC.is()) + { + xub_StrLen nTmpPos = aPaM.GetIndex(); + sal_Int16 nCheckMode = aCTLOptions.IsCTLSequenceCheckingRestricted() ? + i18n::InputSequenceCheckMode::STRICT : i18n::InputSequenceCheckMode::BASIC; + + // the text that needs to be checked is only the one + // before the current cursor position + rtl::OUString aOldText( mpDoc->GetText( aPaM.GetPara() ).Copy(0, nTmpPos) ); + rtl::OUString aNewText( aOldText ); + if (aCTLOptions.IsCTLSequenceCheckingTypeAndReplace()) + { + xISC->correctInputSequence( aNewText, nTmpPos - 1, c, nCheckMode ); + + // find position of first character that has changed + sal_Int32 nOldLen = aOldText.getLength(); + sal_Int32 nNewLen = aNewText.getLength(); + const sal_Unicode *pOldTxt = aOldText.getStr(); + const sal_Unicode *pNewTxt = aNewText.getStr(); + sal_Int32 nChgPos = 0; + while ( nChgPos < nOldLen && nChgPos < nNewLen && + pOldTxt[nChgPos] == pNewTxt[nChgPos] ) + ++nChgPos; + + String aChgText( aNewText.copy( nChgPos ) ); + + // select text from first pos to be changed to current pos + TextSelection aSel( TextPaM( aPaM.GetPara(), (sal_uInt16) nChgPos ), aPaM ); + + if (aChgText.Len()) + // ImpInsertText implicitly handles undo... + return ImpInsertText( aSel, aChgText ); + else + return aPaM; + } + else + { + // should the character be ignored (i.e. not get inserted) ? + if (!xISC->checkInputSequence( aOldText, nTmpPos - 1, c, nCheckMode )) + return aPaM; // nothing to be done -> no need for undo + } + } + + // at this point now we will insert the character 'normally' some lines below... + } + + + if ( IsUndoEnabled() && !IsInUndo() ) + { + TextUndoInsertChars* pNewUndo = new TextUndoInsertChars( this, aPaM, rtl::OUString(c) ); + sal_Bool bTryMerge = ( !bDoOverwrite && ( c != ' ' ) ) ? sal_True : sal_False; + InsertUndo( pNewUndo, bTryMerge ); + } + + TEParaPortion* pPortion = mpTEParaPortions->GetObject( aPaM.GetPara() ); + pPortion->MarkInvalid( aPaM.GetIndex(), 1 ); + if ( c == '\t' ) + pPortion->SetNotSimpleInvalid(); + aPaM = mpDoc->InsertText( aPaM, c ); + ImpCharsInserted( aPaM.GetPara(), aPaM.GetIndex()-1, 1 ); + + TextModified(); + + if ( bUndoAction ) + UndoActionEnd(); + } + + return aPaM; +} + + +TextPaM TextEngine::ImpInsertText( const TextSelection& rCurSel, const XubString& rStr ) +{ + UndoActionStart(); + + TextPaM aPaM; + + if ( rCurSel.HasRange() ) + aPaM = ImpDeleteText( rCurSel ); + else + aPaM = rCurSel.GetEnd(); + + XubString aText(convertLineEnd(rStr, LINEEND_LF)); + + sal_uInt16 nStart = 0; + while ( nStart < aText.Len() ) + { + sal_uInt16 nEnd = aText.Search( LINE_SEP, nStart ); + if ( nEnd == STRING_NOTFOUND ) + nEnd = aText.Len(); // nicht dereferenzieren! + + // Start == End => Leerzeile + if ( nEnd > nStart ) + { + sal_uLong nL = aPaM.GetIndex(); + nL += ( nEnd-nStart ); + if ( nL > STRING_MAXLEN ) + { + sal_uInt16 nDiff = (sal_uInt16) (nL-STRING_MAXLEN); + nEnd = nEnd - nDiff; + } + + XubString aLine( aText, nStart, nEnd-nStart ); + if ( IsUndoEnabled() && !IsInUndo() ) + InsertUndo( new TextUndoInsertChars( this, aPaM, aLine ) ); + + TEParaPortion* pPortion = mpTEParaPortions->GetObject( aPaM.GetPara() ); + pPortion->MarkInvalid( aPaM.GetIndex(), aLine.Len() ); + if ( aLine.Search( '\t' ) != STRING_NOTFOUND ) + pPortion->SetNotSimpleInvalid(); + + aPaM = mpDoc->InsertText( aPaM, aLine ); + ImpCharsInserted( aPaM.GetPara(), aPaM.GetIndex()-aLine.Len(), aLine.Len() ); + + } + if ( nEnd < aText.Len() ) + aPaM = ImpInsertParaBreak( aPaM ); + + nStart = nEnd+1; + + if ( nStart < nEnd ) // #108611# overflow + break; + } + + UndoActionEnd(); + + TextModified(); + return aPaM; +} + +TextPaM TextEngine::ImpInsertParaBreak( const TextSelection& rCurSel, sal_Bool bKeepEndingAttribs ) +{ + TextPaM aPaM; + if ( rCurSel.HasRange() ) + aPaM = ImpDeleteText( rCurSel ); + else + aPaM = rCurSel.GetEnd(); + + return ImpInsertParaBreak( aPaM, bKeepEndingAttribs ); +} + +TextPaM TextEngine::ImpInsertParaBreak( const TextPaM& rPaM, sal_Bool bKeepEndingAttribs ) +{ + if ( IsUndoEnabled() && !IsInUndo() ) + InsertUndo( new TextUndoSplitPara( this, rPaM.GetPara(), rPaM.GetIndex() ) ); + + TextNode* pNode = mpDoc->GetNodes().GetObject( rPaM.GetPara() ); + sal_Bool bFirstParaContentChanged = rPaM.GetIndex() < pNode->GetText().Len(); + + TextPaM aPaM( mpDoc->InsertParaBreak( rPaM, bKeepEndingAttribs ) ); + + TEParaPortion* pPortion = mpTEParaPortions->GetObject( rPaM.GetPara() ); + DBG_ASSERT( pPortion, "Blinde Portion in ImpInsertParaBreak" ); + pPortion->MarkInvalid( rPaM.GetIndex(), 0 ); + + TextNode* pNewNode = mpDoc->GetNodes().GetObject( aPaM.GetPara() ); + TEParaPortion* pNewPortion = new TEParaPortion( pNewNode ); + mpTEParaPortions->Insert( pNewPortion, aPaM.GetPara() ); + ImpParagraphInserted( aPaM.GetPara() ); + + CursorMoved( rPaM.GetPara() ); // falls leeres Attribut entstanden. + TextModified(); + + if ( bFirstParaContentChanged ) + Broadcast( TextHint( TEXT_HINT_PARACONTENTCHANGED, rPaM.GetPara() ) ); + + return aPaM; +} + +Rectangle TextEngine::PaMtoEditCursor( const TextPaM& rPaM, sal_Bool bSpecial ) +{ + DBG_ASSERT( GetUpdateMode(), "Darf bei Update=sal_False nicht erreicht werden: PaMtoEditCursor" ); + + Rectangle aEditCursor; + long nY = 0; + + if ( !mbHasMultiLineParas ) + { + nY = rPaM.GetPara() * mnCharHeight; + } + else + { + for ( sal_uLong nPortion = 0; nPortion < rPaM.GetPara(); nPortion++ ) + { + TEParaPortion* pPortion = mpTEParaPortions->GetObject(nPortion); + nY += pPortion->GetLines().size() * mnCharHeight; + } + } + + aEditCursor = GetEditCursor( rPaM, bSpecial ); + aEditCursor.Top() += nY; + aEditCursor.Bottom() += nY; + return aEditCursor; +} + +Rectangle TextEngine::GetEditCursor( const TextPaM& rPaM, sal_Bool bSpecial, sal_Bool bPreferPortionStart ) +{ + if ( !IsFormatted() && !IsFormatting() ) + FormatAndUpdate(); + + TEParaPortion* pPortion = mpTEParaPortions->GetObject( rPaM.GetPara() ); + //TextNode* pNode = mpDoc->GetNodes().GetObject( rPaM.GetPara() ); + + /* + bSpecial: Wenn hinter dem letzten Zeichen einer umgebrochenen Zeile, + am Ende der Zeile bleiben, nicht am Anfang der naechsten. + Zweck: - END => wirklich hinter das letzte Zeichen + - Selektion.... + bSpecial: If behind the last character of a made up line, stay at the + end of the line, not at the start of the next line. + Purpose: - really END = > behind the last character + - to selection... + + */ + + long nY = 0; + sal_uInt16 nCurIndex = 0; + TextLine* pLine = 0; + for ( sal_uInt16 nLine = 0; nLine < pPortion->GetLines().size(); nLine++ ) + { + TextLine* pTmpLine = pPortion->GetLines()[ nLine ]; + if ( ( pTmpLine->GetStart() == rPaM.GetIndex() ) || ( pTmpLine->IsIn( rPaM.GetIndex(), bSpecial ) ) ) + { + pLine = pTmpLine; + break; + } + + nCurIndex = nCurIndex + pTmpLine->GetLen(); + nY += mnCharHeight; + } + if ( !pLine ) + { + // Cursor am Ende des Absatzes. + DBG_ASSERT( rPaM.GetIndex() == nCurIndex, "Index voll daneben in GetEditCursor!" ); + + pLine = pPortion->GetLines().back(); + nY -= mnCharHeight; + nCurIndex = nCurIndex - pLine->GetLen(); + } + + Rectangle aEditCursor; + + aEditCursor.Top() = nY; + nY += mnCharHeight; + aEditCursor.Bottom() = nY-1; + + // innerhalb der Zeile suchen.... + long nX = ImpGetXPos( rPaM.GetPara(), pLine, rPaM.GetIndex(), bPreferPortionStart ); + aEditCursor.Left() = aEditCursor.Right() = nX; + return aEditCursor; +} + +long TextEngine::ImpGetXPos( sal_uLong nPara, TextLine* pLine, sal_uInt16 nIndex, sal_Bool bPreferPortionStart ) +{ + DBG_ASSERT( ( nIndex >= pLine->GetStart() ) && ( nIndex <= pLine->GetEnd() ) , "ImpGetXPos muss richtig gerufen werden!" ); + + sal_Bool bDoPreferPortionStart = bPreferPortionStart; + // Assure that the portion belongs to this line: + if ( nIndex == pLine->GetStart() ) + bDoPreferPortionStart = sal_True; + else if ( nIndex == pLine->GetEnd() ) + bDoPreferPortionStart = sal_False; + + TEParaPortion* pParaPortion = mpTEParaPortions->GetObject( nPara ); + + sal_uInt16 nTextPortionStart = 0; + size_t nTextPortion = pParaPortion->GetTextPortions().FindPortion( nIndex, nTextPortionStart, bDoPreferPortionStart ); + + DBG_ASSERT( ( nTextPortion >= pLine->GetStartPortion() ) && ( nTextPortion <= pLine->GetEndPortion() ), "GetXPos: Portion not in current line! " ); + + TETextPortion* pPortion = pParaPortion->GetTextPortions()[ nTextPortion ]; + + long nX = ImpGetPortionXOffset( nPara, pLine, nTextPortion ); + + long nPortionTextWidth = pPortion->GetWidth(); + + if ( nTextPortionStart != nIndex ) + { + // Search within portion... + if ( nIndex == ( nTextPortionStart + pPortion->GetLen() ) ) + { + // End of Portion + if ( ( pPortion->GetKind() == PORTIONKIND_TAB ) || + ( !IsRightToLeft() && !pPortion->IsRightToLeft() ) || + ( IsRightToLeft() && pPortion->IsRightToLeft() ) ) + { + nX += nPortionTextWidth; + if ( ( pPortion->GetKind() == PORTIONKIND_TAB ) && ( (nTextPortion+1) < pParaPortion->GetTextPortions().size() ) ) + { + TETextPortion* pNextPortion = pParaPortion->GetTextPortions()[ nTextPortion+1 ]; + if ( ( pNextPortion->GetKind() != PORTIONKIND_TAB ) && ( + ( !IsRightToLeft() && pNextPortion->IsRightToLeft() ) || + ( IsRightToLeft() && !pNextPortion->IsRightToLeft() ) ) ) + { +// nX += pNextPortion->GetWidth(); + // End of the tab portion, use start of next for cursor pos + DBG_ASSERT( !bPreferPortionStart, "ImpGetXPos - How can we this tab portion here???" ); + nX = ImpGetXPos( nPara, pLine, nIndex, sal_True ); + } + + } + } + } + else if ( pPortion->GetKind() == PORTIONKIND_TEXT ) + { + DBG_ASSERT( nIndex != pLine->GetStart(), "Strange behavior in new ImpGetXPos()" ); + + long nPosInPortion = (long)CalcTextWidth( nPara, nTextPortionStart, nIndex-nTextPortionStart ); + + if ( ( !IsRightToLeft() && !pPortion->IsRightToLeft() ) || + ( IsRightToLeft() && pPortion->IsRightToLeft() ) ) + { + nX += nPosInPortion; + } + else + { + nX += nPortionTextWidth - nPosInPortion; + } + } + } + else // if ( nIndex == pLine->GetStart() ) + { + if ( ( pPortion->GetKind() != PORTIONKIND_TAB ) && + ( ( !IsRightToLeft() && pPortion->IsRightToLeft() ) || + ( IsRightToLeft() && !pPortion->IsRightToLeft() ) ) ) + { + nX += nPortionTextWidth; + } + } + + return nX; +} + +const TextAttrib* TextEngine::FindAttrib( const TextPaM& rPaM, sal_uInt16 nWhich ) const +{ + const TextAttrib* pAttr = NULL; + const TextCharAttrib* pCharAttr = FindCharAttrib( rPaM, nWhich ); + if ( pCharAttr ) + pAttr = &pCharAttr->GetAttr(); + return pAttr; +} + +const TextCharAttrib* TextEngine::FindCharAttrib( const TextPaM& rPaM, sal_uInt16 nWhich ) const +{ + const TextCharAttrib* pAttr = NULL; + TextNode* pNode = mpDoc->GetNodes().GetObject( rPaM.GetPara() ); + if ( pNode && ( rPaM.GetIndex() < pNode->GetText().Len() ) ) + pAttr = pNode->GetCharAttribs().FindAttrib( nWhich, rPaM.GetIndex() ); + return pAttr; +} + +sal_Bool TextEngine::HasAttrib( sal_uInt16 nWhich ) const +{ + sal_Bool bAttr = sal_False; + for ( sal_uLong n = mpDoc->GetNodes().Count(); --n && !bAttr; ) + { + TextNode* pNode = mpDoc->GetNodes().GetObject( n ); + bAttr = pNode->GetCharAttribs().HasAttrib( nWhich ); + } + return bAttr; +} + +TextPaM TextEngine::GetPaM( const Point& rDocPos, sal_Bool bSmart ) +{ + DBG_ASSERT( GetUpdateMode(), "Darf bei Update=sal_False nicht erreicht werden: GetPaM" ); + + long nY = 0; + for ( sal_uLong nPortion = 0; nPortion < mpTEParaPortions->Count(); nPortion++ ) + { + TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPortion ); + long nTmpHeight = pPortion->GetLines().size() * mnCharHeight; + nY += nTmpHeight; + if ( nY > rDocPos.Y() ) + { + nY -= nTmpHeight; + Point aPosInPara( rDocPos ); + aPosInPara.Y() -= nY; + + TextPaM aPaM( nPortion, 0 ); + aPaM.GetIndex() = ImpFindIndex( nPortion, aPosInPara, bSmart ); + return aPaM; + } + } + + // Nicht gefunden - Dann den letzten sichtbare... + sal_uLong nLastNode = mpDoc->GetNodes().Count() - 1; + TextNode* pLast = mpDoc->GetNodes().GetObject( nLastNode ); + return TextPaM( nLastNode, pLast->GetText().Len() ); +} + +sal_uInt16 TextEngine::ImpFindIndex( sal_uLong nPortion, const Point& rPosInPara, sal_Bool bSmart ) +{ + DBG_ASSERT( IsFormatted(), "GetPaM: Nicht formatiert" ); + TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPortion ); + + sal_uInt16 nCurIndex = 0; + + long nY = 0; + TextLine* pLine = 0; + sal_uInt16 nLine; + for ( nLine = 0; nLine < pPortion->GetLines().size(); nLine++ ) + { + TextLine* pTmpLine = pPortion->GetLines()[ nLine ]; + nY += mnCharHeight; + if ( nY > rPosInPara.Y() ) // das war 'se + { + pLine = pTmpLine; + break; // richtige Y-Position intressiert nicht + } + } + DBG_ASSERT( pLine, "ImpFindIndex: pLine ?" ); + + nCurIndex = GetCharPos( nPortion, nLine, rPosInPara.X(), bSmart ); + + if ( nCurIndex && ( nCurIndex == pLine->GetEnd() ) && + ( pLine != pPortion->GetLines().back() ) ) + { + uno::Reference < i18n::XBreakIterator > xBI = GetBreakIterator(); + sal_Int32 nCount = 1; + nCurIndex = (sal_uInt16)xBI->previousCharacters( pPortion->GetNode()->GetText(), nCurIndex, GetLocale(), i18n::CharacterIteratorMode::SKIPCELL, nCount, nCount ); + } + return nCurIndex; +} + +sal_uInt16 TextEngine::GetCharPos( sal_uLong nPortion, sal_uInt16 nLine, long nXPos, sal_Bool ) +{ + + TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPortion ); + TextLine* pLine = pPortion->GetLines()[ nLine ]; + + sal_uInt16 nCurIndex = pLine->GetStart(); + + long nTmpX = pLine->GetStartX(); + if ( nXPos <= nTmpX ) + return nCurIndex; + + for ( sal_uInt16 i = pLine->GetStartPortion(); i <= pLine->GetEndPortion(); i++ ) + { + TETextPortion* pTextPortion = pPortion->GetTextPortions()[ i ]; + nTmpX += pTextPortion->GetWidth(); + + if ( nTmpX > nXPos ) + { + if( pTextPortion->GetLen() > 1 ) + { + nTmpX -= pTextPortion->GetWidth(); // vor die Portion stellen + // Optimieren: Kein GetTextBreak, wenn feste Fontbreite... + Font aFont; + SeekCursor( nPortion, nCurIndex+1, aFont, NULL ); + mpRefDev->SetFont( aFont); + long nPosInPortion = nXPos-nTmpX; + if ( IsRightToLeft() != pTextPortion->IsRightToLeft() ) + nPosInPortion = pTextPortion->GetWidth() - nPosInPortion; + nCurIndex = mpRefDev->GetTextBreak( pPortion->GetNode()->GetText(), nPosInPortion, nCurIndex ); + // MT: GetTextBreak should assure that we are not withing a CTL cell... + } + return nCurIndex; + } + nCurIndex = nCurIndex + pTextPortion->GetLen(); + } + return nCurIndex; +} + + +sal_uLong TextEngine::GetTextHeight() const +{ + DBG_ASSERT( GetUpdateMode(), "Sollte bei Update=sal_False nicht verwendet werden: GetTextHeight" ); + + if ( !IsFormatted() && !IsFormatting() ) + ((TextEngine*)this)->FormatAndUpdate(); + + return mnCurTextHeight; +} + +sal_uLong TextEngine::GetTextHeight( sal_uLong nParagraph ) const +{ + DBG_ASSERT( GetUpdateMode(), "Sollte bei Update=sal_False nicht verwendet werden: GetTextHeight" ); + + if ( !IsFormatted() && !IsFormatting() ) + ((TextEngine*)this)->FormatAndUpdate(); + + return CalcParaHeight( nParagraph ); +} + +sal_uLong TextEngine::CalcTextWidth( sal_uLong nPara ) +{ + sal_uLong nParaWidth = 0; + TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPara ); + for ( sal_uInt16 nLine = pPortion->GetLines().size(); nLine; ) + { + sal_uLong nLineWidth = 0; + TextLine* pLine = pPortion->GetLines()[ --nLine ]; + for ( sal_uInt16 nTP = pLine->GetStartPortion(); nTP <= pLine->GetEndPortion(); nTP++ ) + { + TETextPortion* pTextPortion = pPortion->GetTextPortions()[ nTP ]; + nLineWidth += pTextPortion->GetWidth(); + } + if ( nLineWidth > nParaWidth ) + nParaWidth = nLineWidth; + } + return nParaWidth; +} + +sal_uLong TextEngine::CalcTextWidth() +{ + if ( !IsFormatted() && !IsFormatting() ) + FormatAndUpdate(); + + if ( mnCurTextWidth == 0xFFFFFFFF ) + { + mnCurTextWidth = 0; + for ( sal_uLong nPara = mpTEParaPortions->Count(); nPara; ) + { + sal_uLong nParaWidth = CalcTextWidth( --nPara ); + if ( nParaWidth > mnCurTextWidth ) + mnCurTextWidth = nParaWidth; + } + } + return mnCurTextWidth+1;// Ein breiter, da in CreateLines bei >= umgebrochen wird. +} + +sal_uLong TextEngine::CalcTextHeight() +{ + DBG_ASSERT( GetUpdateMode(), "Sollte bei Update=sal_False nicht verwendet werden: CalcTextHeight" ); + + sal_uLong nY = 0; + for ( sal_uLong nPortion = mpTEParaPortions->Count(); nPortion; ) + nY += CalcParaHeight( --nPortion ); + return nY; +} + +sal_uLong TextEngine::CalcTextWidth( sal_uLong nPara, sal_uInt16 nPortionStart, sal_uInt16 nLen, const Font* pFont ) +{ + // Innerhalb des Textes darf es keinen Portionwechsel (Attribut/Tab) geben! + DBG_ASSERT( mpDoc->GetNodes().GetObject( nPara )->GetText().Search( '\t', nPortionStart ) >= (nPortionStart+nLen), "CalcTextWidth: Tab!" ); + + sal_uLong nWidth; + if ( mnFixCharWidth100 ) + { + nWidth = (sal_uLong)nLen*mnFixCharWidth100/100; + } + else + { + if ( pFont ) + { + if ( !mpRefDev->GetFont().IsSameInstance( *pFont ) ) + mpRefDev->SetFont( *pFont ); + } + else + { + Font aFont; + SeekCursor( nPara, nPortionStart+1, aFont, NULL ); + mpRefDev->SetFont( aFont ); + } + TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); + nWidth = (sal_uLong)mpRefDev->GetTextWidth( pNode->GetText(), nPortionStart, nLen ); + + } + return nWidth; +} + + +sal_uInt16 TextEngine::GetLineCount( sal_uLong nParagraph ) const +{ + DBG_ASSERT( nParagraph < mpTEParaPortions->Count(), "GetLineCount: Out of range" ); + + TEParaPortion* pPPortion = mpTEParaPortions->GetObject( nParagraph ); + if ( pPPortion ) + return pPPortion->GetLines().size(); + + return 0xFFFF; +} + +sal_uInt16 TextEngine::GetLineLen( sal_uLong nParagraph, sal_uInt16 nLine ) const +{ + DBG_ASSERT( nParagraph < mpTEParaPortions->Count(), "GetLineCount: Out of range" ); + + TEParaPortion* pPPortion = mpTEParaPortions->GetObject( nParagraph ); + if ( pPPortion && ( nLine < pPPortion->GetLines().size() ) ) + { + TextLine* pLine = pPPortion->GetLines()[ nLine ]; + return pLine->GetLen(); + } + + return 0xFFFF; +} + +sal_uLong TextEngine::CalcParaHeight( sal_uLong nParagraph ) const +{ + sal_uLong nHeight = 0; + + TEParaPortion* pPPortion = mpTEParaPortions->GetObject( nParagraph ); + DBG_ASSERT( pPPortion, "Absatz nicht gefunden: GetParaHeight" ); + if ( pPPortion ) + nHeight = pPPortion->GetLines().size() * mnCharHeight; + + return nHeight; +} + +void TextEngine::UpdateSelections() +{ +} + +Range TextEngine::GetInvalidYOffsets( sal_uLong nPortion ) +{ + TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPortion ); + sal_uInt16 nLines = pTEParaPortion->GetLines().size(); + sal_uInt16 nLastInvalid, nFirstInvalid = 0; + sal_uInt16 nLine; + for ( nLine = 0; nLine < nLines; nLine++ ) + { + TextLine* pL = pTEParaPortion->GetLines()[ nLine ]; + if ( pL->IsInvalid() ) + { + nFirstInvalid = nLine; + break; + } + } + + for ( nLastInvalid = nFirstInvalid; nLastInvalid < nLines; nLastInvalid++ ) + { + TextLine* pL = pTEParaPortion->GetLines()[ nLine ]; + if ( pL->IsValid() ) + break; + } + + if ( nLastInvalid >= nLines ) + nLastInvalid = nLines-1; + + return Range( nFirstInvalid*mnCharHeight, ((nLastInvalid+1)*mnCharHeight)-1 ); +} + +sal_uLong TextEngine::GetParagraphCount() const +{ + return mpDoc->GetNodes().Count(); +} + +void TextEngine::EnableUndo( sal_Bool bEnable ) +{ + // Beim Umschalten des Modus Liste loeschen: + if ( bEnable != IsUndoEnabled() ) + ResetUndo(); + + mbUndoEnabled = bEnable; +} + +::svl::IUndoManager& TextEngine::GetUndoManager() +{ + if ( !mpUndoManager ) + mpUndoManager = new TextUndoManager( this ); + return *mpUndoManager; +} + +void TextEngine::UndoActionStart( sal_uInt16 nId ) +{ + if ( IsUndoEnabled() && !IsInUndo() ) + { + String aComment; + // ... + GetUndoManager().EnterListAction( aComment, XubString(), nId ); + } +} + +void TextEngine::UndoActionEnd() +{ + if ( IsUndoEnabled() && !IsInUndo() ) + GetUndoManager().LeaveListAction(); +} + +void TextEngine::InsertUndo( TextUndo* pUndo, sal_Bool bTryMerge ) +{ + DBG_ASSERT( !IsInUndo(), "InsertUndo im Undomodus!" ); + GetUndoManager().AddUndoAction( pUndo, bTryMerge ); +} + +void TextEngine::ResetUndo() +{ + if ( mpUndoManager ) + mpUndoManager->Clear(); +} + +void TextEngine::InsertContent( TextNode* pNode, sal_uLong nPara ) +{ + DBG_ASSERT( pNode, "NULL-Pointer in InsertContent! " ); + DBG_ASSERT( IsInUndo(), "InsertContent nur fuer Undo()!" ); + TEParaPortion* pNew = new TEParaPortion( pNode ); + mpTEParaPortions->Insert( pNew, nPara ); + mpDoc->GetNodes().Insert( pNode, nPara ); + ImpParagraphInserted( nPara ); +} + +TextPaM TextEngine::SplitContent( sal_uLong nNode, sal_uInt16 nSepPos ) +{ + #ifdef DBG_UTIL + TextNode* pNode = mpDoc->GetNodes().GetObject( nNode ); + DBG_ASSERT( pNode, "Ungueltiger Node in SplitContent" ); + DBG_ASSERT( IsInUndo(), "SplitContent nur fuer Undo()!" ); + DBG_ASSERT( nSepPos <= pNode->GetText().Len(), "Index im Wald: SplitContent" ); + #endif + TextPaM aPaM( nNode, nSepPos ); + return ImpInsertParaBreak( aPaM ); +} + +TextPaM TextEngine::ConnectContents( sal_uLong nLeftNode ) +{ + DBG_ASSERT( IsInUndo(), "ConnectContent nur fuer Undo()!" ); + return ImpConnectParagraphs( nLeftNode, nLeftNode+1 ); +} + +void TextEngine::SeekCursor( sal_uLong nPara, sal_uInt16 nPos, Font& rFont, OutputDevice* pOutDev ) +{ + rFont = maFont; + if ( pOutDev ) + pOutDev->SetTextColor( maTextColor ); + + TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); + sal_uInt16 nAttribs = pNode->GetCharAttribs().Count(); + for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ ) + { + TextCharAttrib* pAttrib = pNode->GetCharAttribs().GetAttrib( nAttr ); + if ( pAttrib->GetStart() > nPos ) + break; + + // Beim Seeken nicht die Attr beruecksichtigen, die dort beginnen! + // Leere Attribute werden beruecksichtigt( verwendet), da diese + // gerade eingestellt wurden. + // 12.4.95: Doch keine Leeren Attribute verwenden: + // - Wenn gerade eingestellt und leer => keine Auswirkung auf Font + // In einem leeren Absatz eingestellte Zeichen werden sofort wirksam. + if ( ( ( pAttrib->GetStart() < nPos ) && ( pAttrib->GetEnd() >= nPos ) ) + || !pNode->GetText().Len() ) + { + if ( pAttrib->Which() != TEXTATTR_FONTCOLOR ) + { + pAttrib->GetAttr().SetFont(rFont); + } + else + { + if ( pOutDev ) + pOutDev->SetTextColor( ((TextAttribFontColor&)pAttrib->GetAttr()).GetColor() ); + } + } + } + + if ( mpIMEInfos && mpIMEInfos->pAttribs && ( mpIMEInfos->aPos.GetPara() == nPara ) && + ( nPos > mpIMEInfos->aPos.GetIndex() ) && ( nPos <= ( mpIMEInfos->aPos.GetIndex() + mpIMEInfos->nLen ) ) ) + { + sal_uInt16 nAttr = mpIMEInfos->pAttribs[ nPos - mpIMEInfos->aPos.GetIndex() - 1 ]; + if ( nAttr & EXTTEXTINPUT_ATTR_UNDERLINE ) + rFont.SetUnderline( UNDERLINE_SINGLE ); + else if ( nAttr & EXTTEXTINPUT_ATTR_BOLDUNDERLINE ) + rFont.SetUnderline( UNDERLINE_BOLD ); + else if ( nAttr & EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE ) + rFont.SetUnderline( UNDERLINE_DOTTED ); + else if ( nAttr & EXTTEXTINPUT_ATTR_DASHDOTUNDERLINE ) + rFont.SetUnderline( UNDERLINE_DOTTED ); + if ( nAttr & EXTTEXTINPUT_ATTR_REDTEXT ) + rFont.SetColor( Color( COL_RED ) ); + else if ( nAttr & EXTTEXTINPUT_ATTR_HALFTONETEXT ) + rFont.SetColor( Color( COL_LIGHTGRAY ) ); + if ( nAttr & EXTTEXTINPUT_ATTR_HIGHLIGHT ) + { + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + rFont.SetColor( rStyleSettings.GetHighlightTextColor() ); + rFont.SetFillColor( rStyleSettings.GetHighlightColor() ); + rFont.SetTransparent( sal_False ); + } + else if ( nAttr & EXTTEXTINPUT_ATTR_GRAYWAVELINE ) + { + rFont.SetUnderline( UNDERLINE_WAVE ); +// if( pOut ) +// pOut->SetTextLineColor( Color( COL_LIGHTGRAY ) ); + } + } +} + +void TextEngine::FormatAndUpdate( TextView* pCurView ) +{ + if ( mbDowning ) + return ; + + if ( IsInUndo() ) + IdleFormatAndUpdate( pCurView ); + else + { + FormatDoc(); + UpdateViews( pCurView ); + } +} + + +void TextEngine::IdleFormatAndUpdate( TextView* pCurView, sal_uInt16 nMaxTimerRestarts ) +{ + mpIdleFormatter->DoIdleFormat( pCurView, nMaxTimerRestarts ); +} + +void TextEngine::TextModified() +{ + mbFormatted = sal_False; + mbModified = sal_True; +} + +void TextEngine::UpdateViews( TextView* pCurView ) +{ + if ( !GetUpdateMode() || IsFormatting() || maInvalidRec.IsEmpty() ) + return; + + DBG_ASSERT( IsFormatted(), "UpdateViews: Doc nicht formatiert!" ); + + for ( sal_uInt16 nView = 0; nView < mpViews->size(); nView++ ) + { + TextView* pView = (*mpViews)[ nView ]; + pView->HideCursor(); + + Rectangle aClipRec( maInvalidRec ); + Size aOutSz = pView->GetWindow()->GetOutputSizePixel(); + Rectangle aVisArea( pView->GetStartDocPos(), aOutSz ); + aClipRec.Intersection( aVisArea ); + if ( !aClipRec.IsEmpty() ) + { + // in Fensterkoordinaten umwandeln.... + Point aNewPos = pView->GetWindowPos( aClipRec.TopLeft() ); + if ( IsRightToLeft() ) + aNewPos.X() -= aOutSz.Width() - 1; + aClipRec.SetPos( aNewPos ); + + if ( pView == pCurView ) + pView->ImpPaint( aClipRec, !pView->GetWindow()->IsPaintTransparent() ); + else + pView->GetWindow()->Invalidate( aClipRec ); + } + } + + if ( pCurView ) + { + pCurView->ShowCursor( pCurView->IsAutoScroll() ); + } + + maInvalidRec = Rectangle(); +} + +IMPL_LINK_NOARG(TextEngine, IdleFormatHdl) +{ + FormatAndUpdate( mpIdleFormatter->GetView() ); + return 0; +} + +void TextEngine::CheckIdleFormatter() +{ + mpIdleFormatter->ForceTimeout(); +} + +void TextEngine::FormatFullDoc() +{ + for ( sal_uLong nPortion = 0; nPortion < mpTEParaPortions->Count(); nPortion++ ) + { + TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPortion ); sal_uInt16 nLen = pTEParaPortion->GetNode()->GetText().Len(); + pTEParaPortion->MarkSelectionInvalid( 0, nLen ); + } + mbFormatted = sal_False; + FormatDoc(); +} + +void TextEngine::FormatDoc() +{ + if ( IsFormatted() || !GetUpdateMode() || IsFormatting() ) + return; + + mbIsFormatting = sal_True; + mbHasMultiLineParas = sal_False; + + long nY = 0; + sal_Bool bGrow = sal_False; + + maInvalidRec = Rectangle(); // leermachen + for ( sal_uLong nPara = 0; nPara < mpTEParaPortions->Count(); nPara++ ) + { + TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); + if ( pTEParaPortion->IsInvalid() ) + { + sal_uLong nOldParaWidth = 0xFFFFFFFF; + if ( mnCurTextWidth != 0xFFFFFFFF ) + nOldParaWidth = CalcTextWidth( nPara ); + + ImpFormattingParagraph( nPara ); + + if ( CreateLines( nPara ) ) + bGrow = sal_True; + + // InvalidRec nur einmal setzen... + if ( maInvalidRec.IsEmpty() ) + { + // Bei Paperwidth 0 (AutoPageSize) bleibt es sonst Empty()... + long nWidth = (long)mnMaxTextWidth; + if ( !nWidth ) + nWidth = 0x7FFFFFFF; + Range aInvRange( GetInvalidYOffsets( nPara ) ); + maInvalidRec = Rectangle( Point( 0, nY+aInvRange.Min() ), + Size( nWidth, aInvRange.Len() ) ); + } + else + { + maInvalidRec.Bottom() = nY + CalcParaHeight( nPara ); + } + + if ( mnCurTextWidth != 0xFFFFFFFF ) + { + sal_uLong nNewParaWidth = CalcTextWidth( nPara ); + if ( nNewParaWidth >= mnCurTextWidth ) + mnCurTextWidth = nNewParaWidth; + else if ( ( nOldParaWidth != 0xFFFFFFFF ) && ( nOldParaWidth >= mnCurTextWidth ) ) + mnCurTextWidth = 0xFFFFFFFF; + } + } + else if ( bGrow ) + { + maInvalidRec.Bottom() = nY + CalcParaHeight( nPara ); + } + nY += CalcParaHeight( nPara ); + if ( !mbHasMultiLineParas && pTEParaPortion->GetLines().size() > 1 ) + mbHasMultiLineParas = sal_True; + } + + if ( !maInvalidRec.IsEmpty() ) + { + sal_uLong nNewHeight = CalcTextHeight(); + long nDiff = nNewHeight - mnCurTextHeight; + if ( nNewHeight < mnCurTextHeight ) + { + maInvalidRec.Bottom() = (long)Max( nNewHeight, mnCurTextHeight ); + if ( maInvalidRec.IsEmpty() ) + { + maInvalidRec.Top() = 0; + // Left und Right werden nicht ausgewertet, aber wegen IsEmpty gesetzt. + maInvalidRec.Left() = 0; + maInvalidRec.Right() = mnMaxTextWidth; + } + } + + mnCurTextHeight = nNewHeight; + if ( nDiff ) + { + mbFormatted = sal_True; + ImpTextHeightChanged(); + } + } + + mbIsFormatting = sal_False; + mbFormatted = sal_True; + + ImpTextFormatted(); +} + +void TextEngine::CreateAndInsertEmptyLine( sal_uLong nPara ) +{ + TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); + TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); + + TextLine* pTmpLine = new TextLine; + pTmpLine->SetStart( pNode->GetText().Len() ); + pTmpLine->SetEnd( pTmpLine->GetStart() ); + pTEParaPortion->GetLines().push_back( pTmpLine ); + + if ( ImpGetAlign() == TXTALIGN_CENTER ) + pTmpLine->SetStartX( (short)(mnMaxTextWidth / 2) ); + else if ( ImpGetAlign() == TXTALIGN_RIGHT ) + pTmpLine->SetStartX( (short)mnMaxTextWidth ); + else + pTmpLine->SetStartX( mpDoc->GetLeftMargin() ); + + sal_Bool bLineBreak = pNode->GetText().Len() ? sal_True : sal_False; + + TETextPortion* pDummyPortion = new TETextPortion( 0 ); + pDummyPortion->GetWidth() = 0; + pTEParaPortion->GetTextPortions().push_back( pDummyPortion ); + + if ( bLineBreak == sal_True ) + { + // -2: The new one is already inserted. + OSL_ENSURE( + pTEParaPortion->GetLines()[pTEParaPortion->GetLines().size()-2], + "Soft Break, no Line?!"); + sal_uInt16 nPos = (sal_uInt16) pTEParaPortion->GetTextPortions().size() - 1 ; + pTmpLine->SetStartPortion( nPos ); + pTmpLine->SetEndPortion( nPos ); + } +} + +void TextEngine::ImpBreakLine( sal_uLong nPara, TextLine* pLine, TETextPortion*, sal_uInt16 nPortionStart, long nRemainingWidth ) +{ + TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); + + // Font sollte noch eingestellt sein. + sal_uInt16 nMaxBreakPos = mpRefDev->GetTextBreak( pNode->GetText(), nRemainingWidth, nPortionStart ); + + DBG_ASSERT( nMaxBreakPos < pNode->GetText().Len(), "Break?!" ); + + if ( nMaxBreakPos == STRING_LEN ) // GetTextBreak() ist anderer Auffassung als GetTextSize() + nMaxBreakPos = pNode->GetText().Len() - 1; + + uno::Reference < i18n::XBreakIterator > xBI = GetBreakIterator(); + i18n::LineBreakHyphenationOptions aHyphOptions( NULL, uno::Sequence< beans::PropertyValue >(), 1 ); + + i18n::LineBreakUserOptions aUserOptions; + aUserOptions.forbiddenBeginCharacters = ImpGetLocaleDataWrapper()->getForbiddenCharacters().beginLine; + aUserOptions.forbiddenEndCharacters = ImpGetLocaleDataWrapper()->getForbiddenCharacters().endLine; + aUserOptions.applyForbiddenRules = sal_True; + aUserOptions.allowPunctuationOutsideMargin = sal_False; + aUserOptions.allowHyphenateEnglish = sal_False; + + static const com::sun::star::lang::Locale aDefLocale; + i18n::LineBreakResults aLBR = xBI->getLineBreak( pNode->GetText(), nMaxBreakPos, aDefLocale, pLine->GetStart(), aHyphOptions, aUserOptions ); + sal_uInt16 nBreakPos = (sal_uInt16)aLBR.breakIndex; + if ( nBreakPos <= pLine->GetStart() ) + { + nBreakPos = nMaxBreakPos; + if ( nBreakPos <= pLine->GetStart() ) + nBreakPos = pLine->GetStart() + 1; // Sonst Endlosschleife! + } + + + // die angeknackste Portion ist die End-Portion + pLine->SetEnd( nBreakPos ); + sal_uInt16 nEndPortion = SplitTextPortion( nPara, nBreakPos ); + + sal_Bool bBlankSeparator = ( ( nBreakPos >= pLine->GetStart() ) && + ( pNode->GetText().GetChar( nBreakPos ) == ' ' ) ) ? sal_True : sal_False; + if ( bBlankSeparator ) + { + // Blanks am Zeilenende generell unterdruecken... + TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); + TETextPortion* pTP = pTEParaPortion->GetTextPortions()[ nEndPortion ]; + DBG_ASSERT( nBreakPos > pLine->GetStart(), "SplitTextPortion am Anfang der Zeile?" ); + pTP->GetWidth() = (long)CalcTextWidth( nPara, nBreakPos-pTP->GetLen(), pTP->GetLen()-1 ); + } + pLine->SetEndPortion( nEndPortion ); +} + +sal_uInt16 TextEngine::SplitTextPortion( sal_uLong nPara, sal_uInt16 nPos ) +{ + + // Die Portion bei nPos wird geplittet, wenn bei nPos nicht + // sowieso ein Wechsel ist + if ( nPos == 0 ) + return 0; + + sal_uInt16 nSplitPortion; + sal_uInt16 nTmpPos = 0; + TETextPortion* pTextPortion = 0; + TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); + sal_uInt16 nPortions = pTEParaPortion->GetTextPortions().size(); + for ( nSplitPortion = 0; nSplitPortion < nPortions; nSplitPortion++ ) + { + TETextPortion* pTP = pTEParaPortion->GetTextPortions()[nSplitPortion]; + nTmpPos = nTmpPos + pTP->GetLen(); + if ( nTmpPos >= nPos ) + { + if ( nTmpPos == nPos ) // dann braucht nichts geteilt werden + return nSplitPortion; + pTextPortion = pTP; + break; + } + } + + DBG_ASSERT( pTextPortion, "Position ausserhalb des Bereichs!" ); + + sal_uInt16 nOverlapp = nTmpPos - nPos; + pTextPortion->GetLen() = pTextPortion->GetLen() - nOverlapp; + TETextPortion* pNewPortion = new TETextPortion( nOverlapp ); + pTEParaPortion->GetTextPortions().insert( pTEParaPortion->GetTextPortions().begin() + nSplitPortion + 1, pNewPortion ); + pTextPortion->GetWidth() = (long)CalcTextWidth( nPara, nPos-pTextPortion->GetLen(), pTextPortion->GetLen() ); + + return nSplitPortion; +} + +void TextEngine::CreateTextPortions( sal_uLong nPara, sal_uInt16 nStartPos ) +{ + TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); + TextNode* pNode = pTEParaPortion->GetNode(); + DBG_ASSERT( pNode->GetText().Len(), "CreateTextPortions sollte nicht fuer leere Absaetze verwendet werden!" ); + + std::set aPositions; + std::set::iterator aPositionsIt; + aPositions.insert(0); + + sal_uInt16 nAttribs = pNode->GetCharAttribs().Count(); + for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ ) + { + TextCharAttrib* pAttrib = pNode->GetCharAttribs().GetAttrib( nAttr ); + + aPositions.insert( pAttrib->GetStart() ); + aPositions.insert( pAttrib->GetEnd() ); + } + aPositions.insert( pNode->GetText().Len() ); + + const std::vector& rWritingDirections = pTEParaPortion->GetWritingDirectionInfos(); + for ( std::vector::const_iterator it = rWritingDirections.begin(); it != rWritingDirections.end(); ++it ) + aPositions.insert( (*it).nStartPos ); + + if ( mpIMEInfos && mpIMEInfos->pAttribs && ( mpIMEInfos->aPos.GetPara() == nPara ) ) + { + sal_uInt16 nLastAttr = 0xFFFF; + for( sal_uInt16 n = 0; n < mpIMEInfos->nLen; n++ ) + { + if ( mpIMEInfos->pAttribs[n] != nLastAttr ) + { + aPositions.insert( mpIMEInfos->aPos.GetIndex() + n ); + nLastAttr = mpIMEInfos->pAttribs[n]; + } + } + } + + sal_uInt16 nTabPos = pNode->GetText().Search( '\t', 0 ); + while ( nTabPos != STRING_NOTFOUND ) + { + aPositions.insert( nTabPos ); + aPositions.insert( nTabPos + 1 ); + nTabPos = pNode->GetText().Search( '\t', nTabPos+1 ); + } + + // Ab ... loeschen: + // Leider muss die Anzahl der TextPortions mit aPositions.Count() + // nicht uebereinstimmen, da evtl. Zeilenumbrueche... + sal_uInt16 nPortionStart = 0; + sal_uInt16 nInvPortion = 0; + sal_uInt16 nP; + for ( nP = 0; nP < pTEParaPortion->GetTextPortions().size(); nP++ ) + { + TETextPortion* pTmpPortion = pTEParaPortion->GetTextPortions()[nP]; + nPortionStart = nPortionStart + pTmpPortion->GetLen(); + if ( nPortionStart >= nStartPos ) + { + nPortionStart = nPortionStart - pTmpPortion->GetLen(); + nInvPortion = nP; + break; + } + } + OSL_ENSURE(nP < pTEParaPortion->GetTextPortions().size() + || pTEParaPortion->GetTextPortions().empty(), + "Nothing to delete: CreateTextPortions"); + if ( nInvPortion && ( nPortionStart+pTEParaPortion->GetTextPortions()[nInvPortion]->GetLen() > nStartPos ) ) + { + // lieber eine davor... + // Aber nur wenn es mitten in der Portion war, sonst ist es evtl. + // die einzige in der Zeile davor ! + nInvPortion--; + nPortionStart = nPortionStart - pTEParaPortion->GetTextPortions()[nInvPortion]->GetLen(); + } + pTEParaPortion->GetTextPortions().DeleteFromPortion( nInvPortion ); + + // Eine Portion kann auch durch einen Zeilenumbruch entstanden sein: + aPositions.insert( nPortionStart ); + + aPositionsIt = aPositions.find( nPortionStart ); + DBG_ASSERT( aPositionsIt != aPositions.end(), "nPortionStart not found" ); + + if ( aPositionsIt != aPositions.end() ) + { + std::set::iterator nextIt = aPositionsIt; + for ( ++nextIt; nextIt != aPositions.end(); ++aPositionsIt, ++nextIt ) + { + TETextPortion* pNew = new TETextPortion( *nextIt - *aPositionsIt ); + pTEParaPortion->GetTextPortions().push_back( pNew ); + } + } + OSL_ENSURE(pTEParaPortion->GetTextPortions().size(), "No Portions?!"); +} + +void TextEngine::RecalcTextPortion( sal_uLong nPara, sal_uInt16 nStartPos, short nNewChars ) +{ + TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); + OSL_ENSURE(pTEParaPortion->GetTextPortions().size(), "no Portions!"); + OSL_ENSURE(nNewChars, "RecalcTextPortion with Diff == 0"); + + TextNode* const pNode = pTEParaPortion->GetNode(); + if ( nNewChars > 0 ) + { + // Wenn an nStartPos ein Attribut beginnt/endet, oder vor nStartPos + // ein Tab steht, faengt eine neue Portion an, + // ansonsten wird die Portion an nStartPos erweitert. + // Oder wenn ganz vorne ( StartPos 0 ) und dann ein Tab + + if ( ( pNode->GetCharAttribs().HasBoundingAttrib( nStartPos ) ) || + ( nStartPos && ( pNode->GetText().GetChar( nStartPos - 1 ) == '\t' ) ) || + ( ( !nStartPos && ( nNewChars < pNode->GetText().Len() ) && pNode->GetText().GetChar( nNewChars ) == '\t' ) ) ) + { + sal_uInt16 nNewPortionPos = 0; + if ( nStartPos ) + nNewPortionPos = SplitTextPortion( nPara, nStartPos ) + 1; + + // Eine leere Portion kann hier stehen, wenn der Absatz leer war, + // oder eine Zeile durch einen harten Zeilenumbruch entstanden ist. + if ( ( nNewPortionPos < pTEParaPortion->GetTextPortions().size() ) && + !pTEParaPortion->GetTextPortions()[nNewPortionPos]->GetLen() ) + { + // Dann die leere Portion verwenden. + sal_uInt16 & r = + pTEParaPortion->GetTextPortions()[nNewPortionPos]->GetLen(); + r = r + nNewChars; + } + else + { + TETextPortion* pNewPortion = new TETextPortion( nNewChars ); + pTEParaPortion->GetTextPortions().insert( pTEParaPortion->GetTextPortions().begin() + nNewPortionPos, pNewPortion ); + } + } + else + { + sal_uInt16 nPortionStart; + const sal_uInt16 nTP = pTEParaPortion->GetTextPortions(). + FindPortion( nStartPos, nPortionStart ); + TETextPortion* const pTP = pTEParaPortion->GetTextPortions()[ nTP ]; + DBG_ASSERT( pTP, "RecalcTextPortion: Portion nicht gefunden" ); + pTP->GetLen() = pTP->GetLen() + nNewChars; + pTP->GetWidth() = (-1); + } + } + else + { + // Portion schrumpfen oder ggf. entfernen. + // Vor Aufruf dieser Methode muss sichergestellt sein, dass + // keine Portions in dem geloeschten Bereich lagen! + + // Es darf keine reinragende oder im Bereich startende Portion geben, + // also muss nStartPos <= nPos <= nStartPos - nNewChars(neg.) sein + sal_uInt16 nPortion = 0; + sal_uInt16 nPos = 0; + sal_uInt16 nEnd = nStartPos-nNewChars; + sal_uInt16 nPortions = pTEParaPortion->GetTextPortions().size(); + TETextPortion* pTP = 0; + for ( nPortion = 0; nPortion < nPortions; nPortion++ ) + { + pTP = pTEParaPortion->GetTextPortions()[ nPortion ]; + if ( ( nPos+pTP->GetLen() ) > nStartPos ) + { + DBG_ASSERT( nPos <= nStartPos, "Start falsch!" ); + DBG_ASSERT( nPos+pTP->GetLen() >= nEnd, "End falsch!" ); + break; + } + nPos = nPos + pTP->GetLen(); + } + DBG_ASSERT( pTP, "RecalcTextPortion: Portion nicht gefunden" ); + if ( ( nPos == nStartPos ) && ( (nPos+pTP->GetLen()) == nEnd ) ) + { + // Portion entfernen; + pTEParaPortion->GetTextPortions().erase( pTEParaPortion->GetTextPortions().begin() + nPortion ); + delete pTP; + } + else + { + DBG_ASSERT( pTP->GetLen() > (-nNewChars), "Portion zu klein zum schrumpfen!" ); + pTP->GetLen() = pTP->GetLen() + nNewChars; + } + OSL_ENSURE( pTEParaPortion->GetTextPortions().size(), + "RecalcTextPortions: none are left!" ); + } +} + +void TextEngine::ImpPaint( OutputDevice* pOutDev, const Point& rStartPos, Rectangle const* pPaintArea, TextSelection const* pPaintRange, TextSelection const* pSelection ) +{ + if ( !GetUpdateMode() ) + return; + + if ( !IsFormatted() ) + FormatDoc(); + + bool bTransparent = false; + Window* pOutWin = dynamic_cast(pOutDev); + bTransparent = (pOutWin && pOutWin->IsPaintTransparent()); + + long nY = rStartPos.Y(); + + TextPaM const* pSelStart = 0; + TextPaM const* pSelEnd = 0; + if ( pSelection && pSelection->HasRange() ) + { + sal_Bool bInvers = pSelection->GetEnd() < pSelection->GetStart(); + pSelStart = !bInvers ? &pSelection->GetStart() : &pSelection->GetEnd(); + pSelEnd = bInvers ? &pSelection->GetStart() : &pSelection->GetEnd(); + } + DBG_ASSERT( !pPaintRange || ( pPaintRange->GetStart() < pPaintRange->GetEnd() ), "ImpPaint: Paint-Range?!" ); + + const StyleSettings& rStyleSettings = pOutDev->GetSettings().GetStyleSettings(); + + // -------------------------------------------------- + // Ueber alle Absaetze... + // -------------------------------------------------- + for ( sal_uLong nPara = 0; nPara < mpTEParaPortions->Count(); nPara++ ) + { + TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPara ); + // falls beim Tippen Idle-Formatierung, asynchrones Paint. + if ( pPortion->IsInvalid() ) + return; + + sal_uLong nParaHeight = CalcParaHeight( nPara ); + if ( ( !pPaintArea || ( ( nY + (long)nParaHeight ) > pPaintArea->Top() ) ) + && ( !pPaintRange || ( ( nPara >= pPaintRange->GetStart().GetPara() ) && ( nPara <= pPaintRange->GetEnd().GetPara() ) ) ) ) + { + // -------------------------------------------------- + // Ueber die Zeilen des Absatzes... + // -------------------------------------------------- + sal_uInt16 nLines = pPortion->GetLines().size(); + sal_uInt16 nIndex = 0; + for ( sal_uInt16 nLine = 0; nLine < nLines; nLine++ ) + { + TextLine* pLine = pPortion->GetLines()[nLine]; + Point aTmpPos( rStartPos.X() + pLine->GetStartX(), nY ); + + if ( ( !pPaintArea || ( ( nY + mnCharHeight ) > pPaintArea->Top() ) ) + && ( !pPaintRange || ( + ( TextPaM( nPara, pLine->GetStart() ) < pPaintRange->GetEnd() ) && + ( TextPaM( nPara, pLine->GetEnd() ) > pPaintRange->GetStart() ) ) ) ) + { + // -------------------------------------------------- + // Ueber die Portions der Zeile... + // -------------------------------------------------- + nIndex = pLine->GetStart(); + for ( sal_uInt16 y = pLine->GetStartPortion(); y <= pLine->GetEndPortion(); y++ ) + { + OSL_ENSURE(pPortion->GetTextPortions().size(), + "Line without Textportion in Paint!"); + TETextPortion* pTextPortion = pPortion->GetTextPortions()[ y ]; + DBG_ASSERT( pTextPortion, "NULL-Pointer im Portioniterator in UpdateViews" ); + + ImpInitLayoutMode( pOutDev /*, pTextPortion->IsRightToLeft() */); + + long nTxtWidth = pTextPortion->GetWidth(); + aTmpPos.X() = rStartPos.X() + ImpGetOutputOffset( nPara, pLine, nIndex, nIndex ); + + // nur ausgeben, was im sichtbaren Bereich beginnt: + if ( ( ( aTmpPos.X() + nTxtWidth ) >= 0 ) + && ( !pPaintRange || ( + ( TextPaM( nPara, nIndex ) < pPaintRange->GetEnd() ) && + ( TextPaM( nPara, nIndex + pTextPortion->GetLen() ) > pPaintRange->GetStart() ) ) ) ) + { + switch ( pTextPortion->GetKind() ) + { + case PORTIONKIND_TEXT: + { + { + Font aFont; + SeekCursor( nPara, nIndex+1, aFont, pOutDev ); + if( bTransparent ) + aFont.SetTransparent( sal_True ); + else if ( pSelection ) + aFont.SetTransparent( sal_False ); + pOutDev->SetFont( aFont ); + + sal_uInt16 nTmpIndex = nIndex; + sal_uInt16 nEnd = nTmpIndex + pTextPortion->GetLen(); + Point aPos = aTmpPos; + if ( pPaintRange ) + { + // evtl soll nicht alles ausgegeben werden... + if ( ( pPaintRange->GetStart().GetPara() == nPara ) + && ( nTmpIndex < pPaintRange->GetStart().GetIndex() ) ) + { + nTmpIndex = pPaintRange->GetStart().GetIndex(); + } + if ( ( pPaintRange->GetEnd().GetPara() == nPara ) + && ( nEnd > pPaintRange->GetEnd().GetIndex() ) ) + { + nEnd = pPaintRange->GetEnd().GetIndex(); + } + } + + sal_Bool bDone = sal_False; + if ( pSelStart ) + { + // liegt ein Teil in der Selektion??? + TextPaM aTextStart( nPara, nTmpIndex ); + TextPaM aTextEnd( nPara, nEnd ); + if ( ( aTextStart < *pSelEnd ) && ( aTextEnd > *pSelStart ) ) + { + sal_uInt16 nL; + + // 1) Bereich vor Selektion + if ( aTextStart < *pSelStart ) + { + nL = pSelStart->GetIndex() - nTmpIndex; + pOutDev->SetFont( aFont); + aPos.X() = rStartPos.X() + ImpGetOutputOffset( nPara, pLine, nTmpIndex, nTmpIndex+nL ); + pOutDev->DrawText( aPos, pPortion->GetNode()->GetText(), nTmpIndex, nL ); + nTmpIndex = nTmpIndex + nL; + + } + // 2) Bereich mit Selektion + nL = nEnd-nTmpIndex; + if ( aTextEnd > *pSelEnd ) + nL = pSelEnd->GetIndex() - nTmpIndex; + if ( nL ) + { + Color aOldTextColor = pOutDev->GetTextColor(); + pOutDev->SetTextColor( rStyleSettings.GetHighlightTextColor() ); + pOutDev->SetTextFillColor( rStyleSettings.GetHighlightColor() ); + aPos.X() = rStartPos.X() + ImpGetOutputOffset( nPara, pLine, nTmpIndex, nTmpIndex+nL ); + pOutDev->DrawText( aPos, pPortion->GetNode()->GetText(), nTmpIndex, nL ); + pOutDev->SetTextColor( aOldTextColor ); + pOutDev->SetTextFillColor(); + nTmpIndex = nTmpIndex + nL; + } + + // 3) Bereich nach Selektion + if ( nTmpIndex < nEnd ) + { + nL = nEnd-nTmpIndex; + aPos.X() = rStartPos.X() + ImpGetOutputOffset( nPara, pLine, nTmpIndex, nTmpIndex+nL ); + pOutDev->DrawText( aPos, pPortion->GetNode()->GetText(), nTmpIndex, nEnd-nTmpIndex ); + } + bDone = sal_True; + } + } + if ( !bDone ) + { + aPos.X() = rStartPos.X() + ImpGetOutputOffset( nPara, pLine, nTmpIndex, nEnd ); + pOutDev->DrawText( aPos, pPortion->GetNode()->GetText(), nTmpIndex, nEnd-nTmpIndex ); + } + } + + } + break; + case PORTIONKIND_TAB: + { + // Bei HideSelection() nur Range, pSelection = 0. + if ( pSelStart || pPaintRange ) + { + Rectangle aTabArea( aTmpPos, Point( aTmpPos.X()+nTxtWidth, aTmpPos.Y()+mnCharHeight-1 ) ); + sal_Bool bDone = sal_False; + if ( pSelStart ) + { + // liegt der Tab in der Selektion??? + TextPaM aTextStart( nPara, nIndex ); + TextPaM aTextEnd( nPara, nIndex+1 ); + if ( ( aTextStart < *pSelEnd ) && ( aTextEnd > *pSelStart ) ) + { + Color aOldColor = pOutDev->GetFillColor(); + pOutDev->SetFillColor( rStyleSettings.GetHighlightColor() ); + pOutDev->DrawRect( aTabArea ); + pOutDev->SetFillColor( aOldColor ); + bDone = sal_True; + } + } + if ( !bDone ) + { + pOutDev->Erase( aTabArea ); + } + } + } + break; + default: OSL_FAIL( "ImpPaint: Unknown Portion-Type !" ); + } + } + + nIndex = nIndex + pTextPortion->GetLen(); + } + } + + nY += mnCharHeight; + + if ( pPaintArea && ( nY >= pPaintArea->Bottom() ) ) + break; // keine sichtbaren Aktionen mehr... + } + } + else + { + nY += nParaHeight; + } + + if ( pPaintArea && ( nY > pPaintArea->Bottom() ) ) + break; // keine sichtbaren Aktionen mehr... + } +} + +sal_Bool TextEngine::CreateLines( sal_uLong nPara ) +{ + // sal_Bool: Aenderung der Hoehe des Absatzes Ja/Nein - sal_True/sal_False + + TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); + TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); + DBG_ASSERT( pTEParaPortion->IsInvalid(), "CreateLines: Portion nicht invalid!" ); + + sal_uInt16 nOldLineCount = pTEParaPortion->GetLines().size(); + + // --------------------------------------------------------------- + // Schnelle Sonderbehandlung fuer leere Absaetze... + // --------------------------------------------------------------- + if ( pTEParaPortion->GetNode()->GetText().Len() == 0 ) + { + // schnelle Sonderbehandlung... + if ( !pTEParaPortion->GetTextPortions().empty() ) + pTEParaPortion->GetTextPortions().Reset(); + if ( !pTEParaPortion->GetLines().empty() ) + { + BOOST_FOREACH(TextLine* pLine, pTEParaPortion->GetLines()) + delete pLine; + pTEParaPortion->GetLines().clear(); + } + CreateAndInsertEmptyLine( nPara ); + pTEParaPortion->SetValid(); + return nOldLineCount != pTEParaPortion->GetLines().size(); + } + + // --------------------------------------------------------------- + // Initialisierung...... + // --------------------------------------------------------------- + + if ( pTEParaPortion->GetLines().empty() ) + { + TextLine* pL = new TextLine; + pTEParaPortion->GetLines().push_back( pL ); + } + + const short nInvalidDiff = pTEParaPortion->GetInvalidDiff(); + const sal_uInt16 nInvalidStart = pTEParaPortion->GetInvalidPosStart(); + const sal_uInt16 nInvalidEnd = nInvalidStart + Abs( nInvalidDiff ); + sal_Bool bQuickFormat = sal_False; + + if ( pTEParaPortion->GetWritingDirectionInfos().empty() ) + ImpInitWritingDirections( nPara ); + + if ( pTEParaPortion->GetWritingDirectionInfos().size() == 1 ) + { + if ( pTEParaPortion->IsSimpleInvalid() && ( nInvalidDiff > 0 ) ) + { + bQuickFormat = sal_True; + } + else if ( ( pTEParaPortion->IsSimpleInvalid() ) && ( nInvalidDiff < 0 ) ) + { + // pruefen, ob loeschen ueber Portiongrenzen erfolgte... + sal_uInt16 nStart = nInvalidStart; // DOPPELT !!!!!!!!!!!!!!! + sal_uInt16 nEnd = nStart - nInvalidDiff; // neg. + bQuickFormat = sal_True; + sal_uInt16 nPos = 0; + sal_uInt16 nPortions = pTEParaPortion->GetTextPortions().size(); + for ( sal_uInt16 nTP = 0; nTP < nPortions; nTP++ ) + { + // Es darf kein Start/Ende im geloeschten Bereich liegen. + TETextPortion* const pTP = pTEParaPortion->GetTextPortions()[ nTP ]; + nPos = nPos + pTP->GetLen(); + if ( ( nPos > nStart ) && ( nPos < nEnd ) ) + { + bQuickFormat = sal_False; + break; + } + } + } + } + + if ( bQuickFormat ) + RecalcTextPortion( nPara, nInvalidStart, nInvalidDiff ); + else + CreateTextPortions( nPara, nInvalidStart ); + + // --------------------------------------------------------------- + // Zeile mit InvalidPos suchen, eine Zeile davor beginnen... + // Zeilen flaggen => nicht removen ! + // --------------------------------------------------------------- + + sal_uInt16 nLine = pTEParaPortion->GetLines().size()-1; + for ( sal_uInt16 nL = 0; nL <= nLine; nL++ ) + { + TextLine* pLine = pTEParaPortion->GetLines()[ nL ]; + if ( pLine->GetEnd() > nInvalidStart ) + { + nLine = nL; + break; + } + pLine->SetValid(); + } + // Eine Zeile davor beginnen... + // Wenn ganz hinten getippt wird, kann sich die Zeile davor nicht aendern. + if ( nLine && ( !pTEParaPortion->IsSimpleInvalid() || ( nInvalidEnd < pNode->GetText().Len() ) || ( nInvalidDiff <= 0 ) ) ) + nLine--; + + TextLine* pLine = pTEParaPortion->GetLines()[ nLine ]; + + // --------------------------------------------------------------- + // Ab hier alle Zeilen durchformatieren... + // --------------------------------------------------------------- + size_t nDelFromLine = std::numeric_limits::max(); + sal_Bool bLineBreak = sal_False; + + sal_uInt16 nIndex = pLine->GetStart(); + TextLine aSaveLine( *pLine ); + + Font aFont; + + sal_Bool bCalcPortion = sal_True; + + while ( nIndex < pNode->GetText().Len() ) + { + sal_Bool bEOL = sal_False; + sal_uInt16 nPortionStart = 0; + sal_uInt16 nPortionEnd = 0; + + sal_uInt16 nTmpPos = nIndex; + sal_uInt16 nTmpPortion = pLine->GetStartPortion(); + long nTmpWidth = mpDoc->GetLeftMargin(); +// long nXWidth = mnMaxTextWidth ? ( mnMaxTextWidth - mpDoc->GetLeftMargin() ) : 0x7FFFFFFF; + // Margin nicht abziehen, ist schon in TmpWidth enthalten. + long nXWidth = mnMaxTextWidth ? mnMaxTextWidth : 0x7FFFFFFF; + if ( nXWidth < nTmpWidth ) + nXWidth = nTmpWidth; + + // Portion suchen, die nicht mehr in Zeile passt.... + TETextPortion* pPortion = 0; + sal_Bool bBrokenLine = sal_False; + bLineBreak = sal_False; + + while ( ( nTmpWidth <= nXWidth ) && !bEOL && ( nTmpPortion < pTEParaPortion->GetTextPortions().size() ) ) + { + nPortionStart = nTmpPos; + pPortion = pTEParaPortion->GetTextPortions()[ nTmpPortion ]; + DBG_ASSERT( pPortion->GetLen(), "Leere Portion in CreateLines ?!" ); + if ( pNode->GetText().GetChar( nTmpPos ) == '\t' ) + { + long nCurPos = nTmpWidth-mpDoc->GetLeftMargin(); + nTmpWidth = ((nCurPos/mnDefTab)+1)*mnDefTab+mpDoc->GetLeftMargin(); + pPortion->GetWidth() = nTmpWidth - nCurPos - mpDoc->GetLeftMargin(); + // Wenn dies das erste Token in der Zeile ist, und + // nTmpWidth > aPaperSize.Width, habe ich eine Endlos-Schleife! + if ( ( nTmpWidth >= nXWidth ) && ( nTmpPortion == pLine->GetStartPortion() ) ) + { + // Aber was jetzt ? Tab passend machen! + pPortion->GetWidth() = nXWidth-1; + nTmpWidth = pPortion->GetWidth(); + bEOL = sal_True; + bBrokenLine = sal_True; + } + pPortion->GetKind() = PORTIONKIND_TAB; + } + else + { + + if ( bCalcPortion || !pPortion->HasValidSize() ) + pPortion->GetWidth() = (long)CalcTextWidth( nPara, nTmpPos, pPortion->GetLen() ); + nTmpWidth += pPortion->GetWidth(); + + pPortion->GetRightToLeft() = ImpGetRightToLeft( nPara, nTmpPos+1 ); + pPortion->GetKind() = PORTIONKIND_TEXT; + } + + nTmpPos = nTmpPos + pPortion->GetLen(); + nPortionEnd = nTmpPos; + nTmpPortion++; + } + + // das war evtl. eine Portion zu weit: + sal_Bool bFixedEnd = sal_False; + if ( nTmpWidth > nXWidth ) + { + nPortionEnd = nTmpPos; + nTmpPos = nTmpPos - pPortion->GetLen(); + nPortionStart = nTmpPos; + nTmpPortion--; + bEOL = sal_False; + + nTmpWidth -= pPortion->GetWidth(); + if ( pPortion->GetKind() == PORTIONKIND_TAB ) + { + bEOL = sal_True; + bFixedEnd = sal_True; + } + } + else + { + bEOL = sal_True; + pLine->SetEnd( nPortionEnd ); + OSL_ENSURE(pTEParaPortion->GetTextPortions().size(), + "No TextPortions?"); + pLine->SetEndPortion( (sal_uInt16)pTEParaPortion->GetTextPortions().size() - 1 ); + } + + if ( bFixedEnd ) + { + pLine->SetEnd( nPortionStart ); + pLine->SetEndPortion( nTmpPortion-1 ); + } + else if ( bLineBreak || bBrokenLine ) + { + pLine->SetEnd( nPortionStart+1 ); + pLine->SetEndPortion( nTmpPortion-1 ); + } + else if ( !bEOL ) + { + DBG_ASSERT( (nPortionEnd-nPortionStart) == pPortion->GetLen(), "Doch eine andere Portion?!" ); + long nRemainingWidth = mnMaxTextWidth - nTmpWidth; + ImpBreakLine( nPara, pLine, pPortion, nPortionStart, nRemainingWidth ); + } + + if ( ( ImpGetAlign() == TXTALIGN_CENTER ) || ( ImpGetAlign() == TXTALIGN_RIGHT ) ) + { + // Ausrichten... + long nTextWidth = 0; + for ( sal_uInt16 nTP = pLine->GetStartPortion(); nTP <= pLine->GetEndPortion(); nTP++ ) + { + TETextPortion* pTextPortion = pTEParaPortion->GetTextPortions()[ nTP ]; + nTextWidth += pTextPortion->GetWidth(); + } + long nSpace = mnMaxTextWidth - nTextWidth; + if ( nSpace > 0 ) + { + if ( ImpGetAlign() == TXTALIGN_CENTER ) + pLine->SetStartX( (sal_uInt16)(nSpace / 2) ); + else // TXTALIGN_RIGHT + pLine->SetStartX( (sal_uInt16)nSpace ); + } + } + else + { + pLine->SetStartX( mpDoc->GetLeftMargin() ); + } + + // ----------------------------------------------------------------- + // pruefen, ob die Zeile neu ausgegeben werden muss... + // ----------------------------------------------------------------- + pLine->SetInvalid(); + + if ( pTEParaPortion->IsSimpleInvalid() ) + { + // Aenderung durch einfache Textaenderung... + // Formatierung nicht abbrechen, da Portions evtl. wieder + // gesplittet werden muessen! + // Wenn irgendwann mal abbrechbar, dann fogende Zeilen Validieren! + // Aber ggf. als Valid markieren, damit weniger Ausgabe... + if ( pLine->GetEnd() < nInvalidStart ) + { + if ( *pLine == aSaveLine ) + { + pLine->SetValid(); + } + } + else + { + sal_uInt16 nStart = pLine->GetStart(); + sal_uInt16 nEnd = pLine->GetEnd(); + + if ( nStart > nInvalidEnd ) + { + if ( ( ( nStart-nInvalidDiff ) == aSaveLine.GetStart() ) && + ( ( nEnd-nInvalidDiff ) == aSaveLine.GetEnd() ) ) + { + pLine->SetValid(); + if ( bCalcPortion && bQuickFormat ) + { + bCalcPortion = sal_False; + pTEParaPortion->CorrectValuesBehindLastFormattedLine( nLine ); + break; + } + } + } + else if ( bQuickFormat && ( nEnd > nInvalidEnd) ) + { + // Wenn die ungueltige Zeile so endet, dass die naechste an + // der 'gleichen' Textstelle wie vorher beginnt, also nicht + // anders umgebrochen wird, brauche ich dort auch nicht die + // textbreiten neu bestimmen: + if ( nEnd == ( aSaveLine.GetEnd() + nInvalidDiff ) ) + { + bCalcPortion = sal_False; + pTEParaPortion->CorrectValuesBehindLastFormattedLine( nLine ); + break; + } + } + } + } + + nIndex = pLine->GetEnd(); // naechste Zeile Start = letzte Zeile Ende + // weil nEnd hinter das letzte Zeichen zeigt! + + sal_uInt16 nEndPortion = pLine->GetEndPortion(); + + // Naechste Zeile oder ggf. neue Zeile.... + pLine = 0; + if ( nLine < pTEParaPortion->GetLines().size()-1 ) + pLine = pTEParaPortion->GetLines()[ ++nLine ]; + if ( pLine && ( nIndex >= pNode->GetText().Len() ) ) + { + nDelFromLine = nLine; + break; + } + if ( !pLine && ( nIndex < pNode->GetText().Len() ) ) + { + pLine = new TextLine; + pTEParaPortion->GetLines().insert( pTEParaPortion->GetLines().begin() + ++nLine, pLine ); + } + if ( pLine ) + { + aSaveLine = *pLine; + pLine->SetStart( nIndex ); + pLine->SetEnd( nIndex ); + pLine->SetStartPortion( nEndPortion+1 ); + pLine->SetEndPortion( nEndPortion+1 ); + } + } // while ( Index < Len ) + + if (nDelFromLine != std::numeric_limits::max()) + { + for( TextLines::iterator it = pTEParaPortion->GetLines().begin() + nDelFromLine; + it != pTEParaPortion->GetLines().end(); ++it ) + { + delete *it; + } + pTEParaPortion->GetLines().erase( pTEParaPortion->GetLines().begin() + nDelFromLine, + pTEParaPortion->GetLines().end() ); + } + + DBG_ASSERT( pTEParaPortion->GetLines().size(), "Keine Zeile nach CreateLines!" ); + + if ( bLineBreak == sal_True ) + CreateAndInsertEmptyLine( nPara ); + + pTEParaPortion->SetValid(); + + return nOldLineCount != pTEParaPortion->GetLines().size(); +} + +String TextEngine::GetWord( const TextPaM& rCursorPos, TextPaM* pStartOfWord ) +{ + String aWord; + if ( rCursorPos.GetPara() < mpDoc->GetNodes().Count() ) + { + TextSelection aSel( rCursorPos ); + TextNode* pNode = mpDoc->GetNodes().GetObject( rCursorPos.GetPara() ); + uno::Reference < i18n::XBreakIterator > xBI = GetBreakIterator(); + i18n::Boundary aBoundary = xBI->getWordBoundary( pNode->GetText(), rCursorPos.GetIndex(), GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True ); + aSel.GetStart().GetIndex() = (sal_uInt16)aBoundary.startPos; + aSel.GetEnd().GetIndex() = (sal_uInt16)aBoundary.endPos; + aWord = pNode->GetText().Copy( aSel.GetStart().GetIndex(), aSel.GetEnd().GetIndex() - aSel.GetStart().GetIndex() ); + if ( pStartOfWord ) + *pStartOfWord = aSel.GetStart(); + } + return aWord; +} + +sal_Bool TextEngine::Read( SvStream& rInput, const TextSelection* pSel ) +{ + sal_Bool bUpdate = GetUpdateMode(); + SetUpdateMode( sal_False ); + + UndoActionStart(); + TextSelection aSel; + if ( pSel ) + aSel = *pSel; + else + { + sal_uLong nParas = mpDoc->GetNodes().Count(); + TextNode* pNode = mpDoc->GetNodes().GetObject( nParas - 1 ); + aSel = TextPaM( nParas-1 , pNode->GetText().Len() ); + } + + if ( aSel.HasRange() ) + aSel = ImpDeleteText( aSel ); + + rtl::OString aLine; + sal_Bool bDone = rInput.ReadLine( aLine ); + rtl::OUString aTmpStr(rtl::OStringToOUString(aLine, rInput.GetStreamCharSet())), aStr; + while ( bDone ) + { + aSel = ImpInsertText( aSel, aTmpStr ); + bDone = rInput.ReadLine( aLine ); + aTmpStr = rtl::OStringToOUString(aLine, rInput.GetStreamCharSet()); + if ( bDone ) + aSel = ImpInsertParaBreak( aSel.GetEnd() ); + } + + UndoActionEnd(); + + TextSelection aNewSel( aSel.GetEnd(), aSel.GetEnd() ); + + // Damit bei FormatAndUpdate nicht auf die ungueltige Selektion zugegriffen wird. + if ( GetActiveView() ) + GetActiveView()->ImpSetSelection( aNewSel ); + + SetUpdateMode( bUpdate ); + FormatAndUpdate( GetActiveView() ); + + return rInput.GetError() ? sal_False : sal_True; +} + +sal_Bool TextEngine::Write( SvStream& rOutput, const TextSelection* pSel, sal_Bool bHTML ) +{ + TextSelection aSel; + if ( pSel ) + aSel = *pSel; + else + { + sal_uLong nParas = mpDoc->GetNodes().Count(); + TextNode* pNode = mpDoc->GetNodes().GetObject( nParas - 1 ); + aSel.GetStart() = TextPaM( 0, 0 ); + aSel.GetEnd() = TextPaM( nParas-1, pNode->GetText().Len() ); + } + + if ( bHTML ) + { + rOutput.WriteLine( "" ); + rOutput.WriteLine( "" ); + } + + for ( sal_uLong nPara = aSel.GetStart().GetPara(); nPara <= aSel.GetEnd().GetPara(); nPara++ ) + { + TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); + + sal_uInt16 nStartPos = 0; + sal_uInt16 nEndPos = pNode->GetText().Len(); + if ( nPara == aSel.GetStart().GetPara() ) + nStartPos = aSel.GetStart().GetIndex(); + if ( nPara == aSel.GetEnd().GetPara() ) + nEndPos = aSel.GetEnd().GetIndex(); + + String aText; + if ( !bHTML ) + { + aText = pNode->GetText().Copy( nStartPos, nEndPos-nStartPos ); + } + else + { + aText.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "

" ) ); + + if ( nStartPos == nEndPos ) + { + // Leerzeilen werden von Writer wegoptimiert + aText.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "
" ) ); + } + else + { + sal_uInt16 nTmpStart = nStartPos; + sal_uInt16 nTmpEnd = nEndPos; + do + { + TextCharAttrib* pAttr = pNode->GetCharAttribs().FindNextAttrib( TEXTATTR_HYPERLINK, nTmpStart, nEndPos ); + nTmpEnd = pAttr ? pAttr->GetStart() : nEndPos; + + // Text vor dem Attribut + aText += pNode->GetText().Copy( nTmpStart, nTmpEnd-nTmpStart ); + + if ( pAttr ) + { + nTmpEnd = Min( pAttr->GetEnd(), nEndPos ); + + // z.B. Morgenpost + aText.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "GetAttr() ).GetURL(); + aText.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "\">" ) ); + nTmpStart = pAttr->GetStart(); + aText += pNode->GetText().Copy( nTmpStart, nTmpEnd-nTmpStart ); + aText.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "" ) ); + + nTmpStart = pAttr->GetEnd(); + } + } while ( nTmpEnd < nEndPos ); + } + + aText.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "

" ) ); + } + rOutput.WriteLine(rtl::OUStringToOString(aText, + rOutput.GetStreamCharSet())); + } + + if ( bHTML ) + { + rOutput.WriteLine( "" ); + rOutput.WriteLine( "" ); + } + + return rOutput.GetError() ? sal_False : sal_True; +} + +void TextEngine::RemoveAttribs( sal_uLong nPara, sal_Bool bIdleFormatAndUpdate ) +{ + if ( nPara < mpDoc->GetNodes().Count() ) + { + TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); + if ( pNode->GetCharAttribs().Count() ) + { + pNode->GetCharAttribs().Clear( sal_True ); + + TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); + pTEParaPortion->MarkSelectionInvalid( 0, pNode->GetText().Len() ); + + mbFormatted = sal_False; + + if ( bIdleFormatAndUpdate ) + IdleFormatAndUpdate( NULL, 0xFFFF ); + else + FormatAndUpdate( NULL ); + } + } +} +void TextEngine::RemoveAttribs( sal_uLong nPara, sal_uInt16 nWhich, sal_Bool bIdleFormatAndUpdate ) +{ + if ( nPara < mpDoc->GetNodes().Count() ) + { + TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); + if ( pNode->GetCharAttribs().Count() ) + { + TextCharAttribList& rAttribs = pNode->GetCharAttribs(); + sal_uInt16 nAttrCount = rAttribs.Count(); + for(sal_uInt16 nAttr = nAttrCount; nAttr; --nAttr) + { + if(rAttribs.GetAttrib( nAttr - 1 )->Which() == nWhich) + rAttribs.RemoveAttrib( nAttr -1 ); + } + TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); + pTEParaPortion->MarkSelectionInvalid( 0, pNode->GetText().Len() ); + mbFormatted = sal_False; + if(bIdleFormatAndUpdate) + IdleFormatAndUpdate( NULL, 0xFFFF ); + else + FormatAndUpdate( NULL ); + } + } +} +void TextEngine::RemoveAttrib( sal_uLong nPara, const TextCharAttrib& rAttrib ) +{ + if ( nPara < mpDoc->GetNodes().Count() ) + { + TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); + if ( pNode->GetCharAttribs().Count() ) + { + TextCharAttribList& rAttribs = pNode->GetCharAttribs(); + sal_uInt16 nAttrCount = rAttribs.Count(); + for(sal_uInt16 nAttr = nAttrCount; nAttr; --nAttr) + { + if(rAttribs.GetAttrib( nAttr - 1 ) == &rAttrib) + { + rAttribs.RemoveAttrib( nAttr -1 ); + break; + } + } + TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); + pTEParaPortion->MarkSelectionInvalid( 0, pNode->GetText().Len() ); + mbFormatted = sal_False; + FormatAndUpdate( NULL ); + } + } +} + +void TextEngine::SetAttrib( const TextAttrib& rAttr, sal_uLong nPara, sal_uInt16 nStart, sal_uInt16 nEnd, sal_Bool bIdleFormatAndUpdate ) +{ + // Es wird hier erstmal nicht geprueft, ob sich Attribute ueberlappen! + // Diese Methode ist erstmal nur fuer einen Editor, der fuer eine Zeile + // _schnell_ das Syntax-Highlight einstellen will. + + // Da die TextEngine z.Zt fuer Editoren gedacht ist gibt es auch kein + // Undo fuer Attribute! + + if ( nPara < mpDoc->GetNodes().Count() ) + { + TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); + TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); + + sal_uInt16 nMax = pNode->GetText().Len(); + if ( nStart > nMax ) + nStart = nMax; + if ( nEnd > nMax ) + nEnd = nMax; + + pNode->GetCharAttribs().InsertAttrib( new TextCharAttrib( rAttr, nStart, nEnd ) ); + pTEParaPortion->MarkSelectionInvalid( nStart, nEnd ); + + mbFormatted = sal_False; + if ( bIdleFormatAndUpdate ) + IdleFormatAndUpdate( NULL, 0xFFFF ); + else + FormatAndUpdate( NULL ); + } +} + +void TextEngine::SetTextAlign( TxtAlign eAlign ) +{ + if ( eAlign != meAlign ) + { + meAlign = eAlign; + FormatFullDoc(); + UpdateViews(); + } +} + + +void TextEngine::ValidateSelection( TextSelection& rSel ) const +{ + ValidatePaM( rSel.GetStart() ); + ValidatePaM( rSel.GetEnd() ); +} + +void TextEngine::ValidatePaM( TextPaM& rPaM ) const +{ + sal_uLong nMaxPara = mpDoc->GetNodes().Count() - 1; + if ( rPaM.GetPara() > nMaxPara ) + { + rPaM.GetPara() = nMaxPara; + rPaM.GetIndex() = 0xFFFF; + } + + sal_uInt16 nMaxIndex = GetTextLen( rPaM.GetPara() ); + if ( rPaM.GetIndex() > nMaxIndex ) + rPaM.GetIndex() = nMaxIndex; +} + + +// Status & Selektionsanpassung + +void TextEngine::ImpParagraphInserted( sal_uLong nPara ) +{ + // Die aktive View braucht nicht angepasst werden, aber bei allen + // passiven muss die Selektion angepasst werden: + if ( mpViews->size() > 1 ) + { + for ( sal_uInt16 nView = mpViews->size(); nView; ) + { + TextView* pView = (*mpViews)[ --nView ]; + if ( pView != GetActiveView() ) + { + for ( int n = 0; n <= 1; n++ ) + { + TextPaM& rPaM = n ? pView->GetSelection().GetStart(): pView->GetSelection().GetEnd(); + if ( rPaM.GetPara() >= nPara ) + rPaM.GetPara()++; + } + } + } + } + Broadcast( TextHint( TEXT_HINT_PARAINSERTED, nPara ) ); +} + +void TextEngine::ImpParagraphRemoved( sal_uLong nPara ) +{ + if ( mpViews->size() > 1 ) + { + for ( sal_uInt16 nView = mpViews->size(); nView; ) + { + TextView* pView = (*mpViews)[ --nView ]; + if ( pView != GetActiveView() ) + { + sal_uLong nParas = mpDoc->GetNodes().Count(); + for ( int n = 0; n <= 1; n++ ) + { + TextPaM& rPaM = n ? pView->GetSelection().GetStart(): pView->GetSelection().GetEnd(); + if ( rPaM.GetPara() > nPara ) + rPaM.GetPara()--; + else if ( rPaM.GetPara() == nPara ) + { + rPaM.GetIndex() = 0; + if ( rPaM.GetPara() >= nParas ) + rPaM.GetPara()--; + } + } + } + } + } + Broadcast( TextHint( TEXT_HINT_PARAREMOVED, nPara ) ); +} + +void TextEngine::ImpCharsRemoved( sal_uLong nPara, sal_uInt16 nPos, sal_uInt16 nChars ) +{ + if ( mpViews->size() > 1 ) + { + for ( sal_uInt16 nView = mpViews->size(); nView; ) + { + TextView* pView = (*mpViews)[ --nView ]; + if ( pView != GetActiveView() ) + { + sal_uInt16 nEnd = nPos+nChars; + for ( int n = 0; n <= 1; n++ ) + { + TextPaM& rPaM = n ? pView->GetSelection().GetStart(): pView->GetSelection().GetEnd(); + if ( rPaM.GetPara() == nPara ) + { + if ( rPaM.GetIndex() > nEnd ) + rPaM.GetIndex() = rPaM.GetIndex() - nChars; + else if ( rPaM.GetIndex() > nPos ) + rPaM.GetIndex() = nPos; + } + } + } + } + } + Broadcast( TextHint( TEXT_HINT_PARACONTENTCHANGED, nPara ) ); +} + +void TextEngine::ImpCharsInserted( sal_uLong nPara, sal_uInt16 nPos, sal_uInt16 nChars ) +{ + if ( mpViews->size() > 1 ) + { + for ( sal_uInt16 nView = mpViews->size(); nView; ) + { + TextView* pView = (*mpViews)[ --nView ]; + if ( pView != GetActiveView() ) + { + for ( int n = 0; n <= 1; n++ ) + { + TextPaM& rPaM = n ? pView->GetSelection().GetStart(): pView->GetSelection().GetEnd(); + if ( rPaM.GetPara() == nPara ) + { + if ( rPaM.GetIndex() >= nPos ) + rPaM.GetIndex() = rPaM.GetIndex() + nChars; + } + } + } + } + } + Broadcast( TextHint( TEXT_HINT_PARACONTENTCHANGED, nPara ) ); +} + +void TextEngine::ImpFormattingParagraph( sal_uLong nPara ) +{ + Broadcast( TextHint( TEXT_HINT_FORMATPARA, nPara ) ); +} + +void TextEngine::ImpTextHeightChanged() +{ + Broadcast( TextHint( TEXT_HINT_TEXTHEIGHTCHANGED ) ); +} + +void TextEngine::ImpTextFormatted() +{ + Broadcast( TextHint( TEXT_HINT_TEXTFORMATTED ) ); +} + +void TextEngine::Draw( OutputDevice* pDev, const Point& rPos ) +{ + ImpPaint( pDev, rPos, NULL ); +} + +void TextEngine::SetLeftMargin( sal_uInt16 n ) +{ + mpDoc->SetLeftMargin( n ); +} + +sal_uInt16 TextEngine::GetLeftMargin() const +{ + return mpDoc->GetLeftMargin(); +} + +uno::Reference< i18n::XBreakIterator > TextEngine::GetBreakIterator() +{ + if ( !mxBreakIterator.is() ) + mxBreakIterator = vcl::unohelper::CreateBreakIterator(); + DBG_ASSERT( mxBreakIterator.is(), "Could not create BreakIterator" ); + return mxBreakIterator; +} + +void TextEngine::SetLocale( const ::com::sun::star::lang::Locale& rLocale ) +{ + maLocale = rLocale; + delete mpLocaleDataWrapper; + mpLocaleDataWrapper = NULL; +} + +::com::sun::star::lang::Locale TextEngine::GetLocale() +{ + if ( maLocale.Language.isEmpty() ) + { + maLocale = Application::GetSettings().GetUILocale(); + } + return maLocale; +} + +LocaleDataWrapper* TextEngine::ImpGetLocaleDataWrapper() +{ + if ( !mpLocaleDataWrapper ) + mpLocaleDataWrapper = new LocaleDataWrapper( vcl::unohelper::GetMultiServiceFactory(), GetLocale() ); + + return mpLocaleDataWrapper; +} + +void TextEngine::SetRightToLeft( sal_Bool bR2L ) +{ + if ( mbRightToLeft != bR2L ) + { + mbRightToLeft = bR2L; + meAlign = bR2L ? TXTALIGN_RIGHT : TXTALIGN_LEFT; + FormatFullDoc(); + UpdateViews(); + } +} + +void TextEngine::ImpInitWritingDirections( sal_uLong nPara ) +{ + TEParaPortion* pParaPortion = mpTEParaPortions->GetObject( nPara ); + std::vector& rInfos = pParaPortion->GetWritingDirectionInfos(); + rInfos.clear(); + + if ( pParaPortion->GetNode()->GetText().Len() ) + { + const UBiDiLevel nBidiLevel = IsRightToLeft() ? 1 /*RTL*/ : 0 /*LTR*/; + String aText( pParaPortion->GetNode()->GetText() ); + + // + // Bidi functions from icu 2.0 + // + UErrorCode nError = U_ZERO_ERROR; + UBiDi* pBidi = ubidi_openSized( aText.Len(), 0, &nError ); + nError = U_ZERO_ERROR; + + ubidi_setPara( pBidi, reinterpret_cast(aText.GetBuffer()), aText.Len(), nBidiLevel, NULL, &nError ); // UChar != sal_Unicode in MinGW + nError = U_ZERO_ERROR; + + long nCount = ubidi_countRuns( pBidi, &nError ); + + int32_t nStart = 0; + int32_t nEnd; + UBiDiLevel nCurrDir; + + for ( sal_uInt16 nIdx = 0; nIdx < nCount; ++nIdx ) + { + ubidi_getLogicalRun( pBidi, nStart, &nEnd, &nCurrDir ); + rInfos.push_back( TEWritingDirectionInfo( nCurrDir, (sal_uInt16)nStart, (sal_uInt16)nEnd ) ); + nStart = nEnd; + } + + ubidi_close( pBidi ); + } + + // No infos mean no CTL and default dir is L2R... + if ( rInfos.empty() ) + rInfos.push_back( TEWritingDirectionInfo( 0, 0, (sal_uInt16)pParaPortion->GetNode()->GetText().Len() ) ); + +} + +sal_uInt8 TextEngine::ImpGetRightToLeft( sal_uLong nPara, sal_uInt16 nPos, sal_uInt16* pStart, sal_uInt16* pEnd ) +{ + sal_uInt8 nRightToLeft = 0; + + TextNode* pNode = mpDoc->GetNodes().GetObject( nPara ); + if ( pNode && pNode->GetText().Len() ) + { + TEParaPortion* pParaPortion = mpTEParaPortions->GetObject( nPara ); + if ( pParaPortion->GetWritingDirectionInfos().empty() ) + ImpInitWritingDirections( nPara ); + + std::vector& rDirInfos = pParaPortion->GetWritingDirectionInfos(); + for ( std::vector::const_iterator rDirInfosIt = rDirInfos.begin(); rDirInfosIt != rDirInfos.end(); ++rDirInfosIt ) + { + if ( ( (*rDirInfosIt).nStartPos <= nPos ) && ( (*rDirInfosIt).nEndPos >= nPos ) ) + { + nRightToLeft = (*rDirInfosIt).nType; + if ( pStart ) + *pStart = (*rDirInfosIt).nStartPos; + if ( pEnd ) + *pEnd = (*rDirInfosIt).nEndPos; + break; + } + } + } + return nRightToLeft; +} + +long TextEngine::ImpGetPortionXOffset( sal_uLong nPara, TextLine* pLine, sal_uInt16 nTextPortion ) +{ + long nX = pLine->GetStartX(); + + TEParaPortion* pParaPortion = mpTEParaPortions->GetObject( nPara ); + + for ( sal_uInt16 i = pLine->GetStartPortion(); i < nTextPortion; i++ ) + { + TETextPortion* pPortion = pParaPortion->GetTextPortions()[ i ]; + nX += pPortion->GetWidth(); + } + + TETextPortion* pDestPortion = pParaPortion->GetTextPortions()[ nTextPortion ]; + if ( pDestPortion->GetKind() != PORTIONKIND_TAB ) + { + if ( !IsRightToLeft() && pDestPortion->GetRightToLeft() ) + { + // Portions behind must be added, visual before this portion + sal_uInt16 nTmpPortion = nTextPortion+1; + while ( nTmpPortion <= pLine->GetEndPortion() ) + { + TETextPortion* pNextTextPortion = pParaPortion->GetTextPortions()[ nTmpPortion ]; + if ( pNextTextPortion->GetRightToLeft() && ( pNextTextPortion->GetKind() != PORTIONKIND_TAB ) ) + nX += pNextTextPortion->GetWidth(); + else + break; + nTmpPortion++; + } + // Portions before must be removed, visual behind this portion + nTmpPortion = nTextPortion; + while ( nTmpPortion > pLine->GetStartPortion() ) + { + --nTmpPortion; + TETextPortion* pPrevTextPortion = pParaPortion->GetTextPortions()[ nTmpPortion ]; + if ( pPrevTextPortion->GetRightToLeft() && ( pPrevTextPortion->GetKind() != PORTIONKIND_TAB ) ) + nX -= pPrevTextPortion->GetWidth(); + else + break; + } + } + else if ( IsRightToLeft() && !pDestPortion->IsRightToLeft() ) + { + // Portions behind must be removed, visual behind this portion + sal_uInt16 nTmpPortion = nTextPortion+1; + while ( nTmpPortion <= pLine->GetEndPortion() ) + { + TETextPortion* pNextTextPortion = pParaPortion->GetTextPortions()[ nTmpPortion ]; + if ( !pNextTextPortion->IsRightToLeft() && ( pNextTextPortion->GetKind() != PORTIONKIND_TAB ) ) + nX += pNextTextPortion->GetWidth(); + else + break; + nTmpPortion++; + } + // Portions before must be added, visual before this portion + nTmpPortion = nTextPortion; + while ( nTmpPortion > pLine->GetStartPortion() ) + { + --nTmpPortion; + TETextPortion* pPrevTextPortion = pParaPortion->GetTextPortions()[ nTmpPortion ]; + if ( !pPrevTextPortion->IsRightToLeft() && ( pPrevTextPortion->GetKind() != PORTIONKIND_TAB ) ) + nX -= pPrevTextPortion->GetWidth(); + else + break; + } + } + } + + return nX; +} + +void TextEngine::ImpInitLayoutMode( OutputDevice* pOutDev, sal_Bool bDrawingR2LPortion ) +{ + sal_uLong nLayoutMode = pOutDev->GetLayoutMode(); + + nLayoutMode &= ~(TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_COMPLEX_DISABLED | TEXT_LAYOUT_BIDI_STRONG ); + if ( bDrawingR2LPortion ) + nLayoutMode |= TEXT_LAYOUT_BIDI_RTL; + + pOutDev->SetLayoutMode( nLayoutMode ); +} + +TxtAlign TextEngine::ImpGetAlign() const +{ + TxtAlign eAlign = meAlign; + if ( IsRightToLeft() ) + { + if ( eAlign == TXTALIGN_LEFT ) + eAlign = TXTALIGN_RIGHT; + else if ( eAlign == TXTALIGN_RIGHT ) + eAlign = TXTALIGN_LEFT; + } + return eAlign; +} + +long TextEngine::ImpGetOutputOffset( sal_uLong nPara, TextLine* pLine, sal_uInt16 nIndex, sal_uInt16 nIndex2 ) +{ + TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPara ); + + sal_uInt16 nPortionStart; + sal_uInt16 nPortion = pPortion->GetTextPortions().FindPortion( nIndex, nPortionStart, sal_True ); + + TETextPortion* pTextPortion = pPortion->GetTextPortions()[ nPortion ]; + + long nX; + + if ( ( nIndex == nPortionStart ) && ( nIndex == nIndex2 ) ) + { + // Output of full portion, so we need portion x offset. + // Use ImpGetPortionXOffset, because GetXPos may deliver left or right position from portioon, depending on R2L, L2R + nX = ImpGetPortionXOffset( nPara, pLine, nPortion ); + if ( IsRightToLeft() ) + { + nX = -nX -pTextPortion->GetWidth(); + } + } + else + { + nX = ImpGetXPos( nPara, pLine, nIndex, nIndex == nPortionStart ); + if ( nIndex2 != nIndex ) + { + long nX2 = ImpGetXPos( nPara, pLine, nIndex2, sal_False ); + if ( ( !IsRightToLeft() && ( nX2 < nX ) ) || + ( IsRightToLeft() && ( nX2 > nX ) ) ) + { + nX = nX2; + } + } + if ( IsRightToLeft() ) + { + nX = -nX; + } + } + + return nX; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/edit/textund2.hxx b/vcl/source/edit/textund2.hxx new file mode 100644 index 0000000..c5ce90c --- /dev/null +++ b/vcl/source/edit/textund2.hxx @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef _TEXTUND2_HXX +#define _TEXTUND2_HXX + +#include + + +class TextUndoDelPara : public TextUndo +{ +private: + sal_Bool mbDelObject; + sal_uLong mnPara; + TextNode* mpNode; // Zeigt auf das gueltige, nicht zerstoerte Objekt! + +public: + TYPEINFO(); + TextUndoDelPara( TextEngine* pTextEngine, TextNode* pNode, sal_uLong nPara ); + ~TextUndoDelPara(); + + virtual void Undo(); + virtual void Redo(); +}; + + +class TextUndoConnectParas : public TextUndo +{ +private: + sal_uLong mnPara; + sal_uInt16 mnSepPos; + +public: + TYPEINFO(); + TextUndoConnectParas( TextEngine* pTextEngine, sal_uLong nPara, sal_uInt16 nSepPos ); + ~TextUndoConnectParas(); + + virtual void Undo(); + virtual void Redo(); +}; + + +class TextUndoSplitPara : public TextUndo +{ +private: + sal_uLong mnPara; + sal_uInt16 mnSepPos; + +public: + TYPEINFO(); + TextUndoSplitPara( TextEngine* pTextEngine, sal_uLong nPara, sal_uInt16 nSepPos ); + ~TextUndoSplitPara(); + + virtual void Undo(); + virtual void Redo(); +}; + + +class TextUndoInsertChars : public TextUndo +{ +private: + TextPaM maTextPaM; + String maText; + +public: + TYPEINFO(); + TextUndoInsertChars( TextEngine* pTextEngine, const TextPaM& rTextPaM, const String& rStr ); + + virtual void Undo(); + virtual void Redo(); + + virtual sal_Bool Merge( SfxUndoAction *pNextAction ); +}; + + +class TextUndoRemoveChars : public TextUndo +{ +private: + TextPaM maTextPaM; + String maText; + +public: + TYPEINFO(); + TextUndoRemoveChars( TextEngine* pTextEngine, const TextPaM& rTextPaM, const String& rStr ); + + virtual void Undo(); + virtual void Redo(); +}; + + +class TextUndoSetAttribs: public TextUndo +{ +private: + TextSelection maSelection; + +public: + TYPEINFO(); + TextUndoSetAttribs( TextEngine* pTextEngine, const TextSelection& rESel ); + ~TextUndoSetAttribs(); + + virtual void Undo(); + virtual void Redo(); +}; + +#endif // _TEXTUND2_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/edit/textundo.cxx b/vcl/source/edit/textundo.cxx new file mode 100644 index 0000000..807abf2 --- /dev/null +++ b/vcl/source/edit/textundo.cxx @@ -0,0 +1,295 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include +#include +#include +#include +#include +#include +#include + +TYPEINIT1( TextUndo, SfxUndoAction ); +TYPEINIT1( TextUndoDelPara, TextUndo ); +TYPEINIT1( TextUndoConnectParas, TextUndo ); +TYPEINIT1( TextUndoSplitPara, TextUndo ); +TYPEINIT1( TextUndoInsertChars, TextUndo ); +TYPEINIT1( TextUndoRemoveChars, TextUndo ); + + +TextUndoManager::TextUndoManager( TextEngine* p ) +{ + mpTextEngine = p; +} + +TextUndoManager::~TextUndoManager() +{ +} + +sal_Bool TextUndoManager::Undo() +{ + if ( GetUndoActionCount() == 0 ) + return sal_False; + + UndoRedoStart(); + + mpTextEngine->SetIsInUndo( sal_True ); + sal_Bool bDone = SfxUndoManager::Undo(); + mpTextEngine->SetIsInUndo( sal_False ); + + UndoRedoEnd(); + + return bDone; +} + +sal_Bool TextUndoManager::Redo() +{ + if ( GetRedoActionCount() == 0 ) + return sal_False; + + + UndoRedoStart(); + + mpTextEngine->SetIsInUndo( sal_True ); + sal_Bool bDone = SfxUndoManager::Redo(); + mpTextEngine->SetIsInUndo( sal_False ); + + UndoRedoEnd(); + + return bDone; +} + +void TextUndoManager::UndoRedoStart() +{ + DBG_ASSERT( GetView(), "Undo/Redo: Active View?" ); + +// if ( GetView() ) +// GetView()->HideSelection(); +} + +void TextUndoManager::UndoRedoEnd() +{ + if ( GetView() ) + { + TextSelection aNewSel( GetView()->GetSelection() ); + aNewSel.GetStart() = aNewSel.GetEnd(); + GetView()->ImpSetSelection( aNewSel ); + } + + mpTextEngine->UpdateSelections(); + + mpTextEngine->FormatAndUpdate( GetView() ); +} + + +TextUndo::TextUndo( TextEngine* p ) +{ + mpTextEngine = p; +} + +TextUndo::~TextUndo() +{ +} + +rtl::OUString TextUndo::GetComment() const +{ + return rtl::OUString(); +} + +void TextUndo::SetSelection( const TextSelection& rSel ) +{ + if ( GetView() ) + GetView()->ImpSetSelection( rSel ); +} + + +TextUndoDelPara::TextUndoDelPara( TextEngine* pTextEngine, TextNode* pNode, sal_uLong nPara ) + : TextUndo( pTextEngine ) +{ + mpNode = pNode; + mnPara = nPara; + mbDelObject = sal_True; +} + +TextUndoDelPara::~TextUndoDelPara() +{ + if ( mbDelObject ) + delete mpNode; +} + +void TextUndoDelPara::Undo() +{ + GetTextEngine()->InsertContent( mpNode, mnPara ); + mbDelObject = sal_False; // gehoert wieder der Engine + + if ( GetView() ) + { + TextSelection aSel( TextPaM( mnPara, 0 ), TextPaM( mnPara, mpNode->GetText().Len() ) ); + SetSelection( aSel ); + } +} + +void TextUndoDelPara::Redo() +{ + // pNode stimmt nicht mehr, falls zwischendurch Undos, in denen + // Absaetze verschmolzen sind. + mpNode = GetDoc()->GetNodes().GetObject( mnPara ); + + delete GetTEParaPortions()->GetObject( mnPara ); + GetTEParaPortions()->Remove( mnPara ); + + // Node nicht loeschen, haengt im Undo! + GetDoc()->GetNodes().Remove( mnPara ); + GetTextEngine()->ImpParagraphRemoved( mnPara ); + + mbDelObject = sal_True; // gehoert wieder dem Undo + + sal_uLong nParas = GetDoc()->GetNodes().Count(); + sal_uLong n = mnPara < nParas ? mnPara : (nParas-1); + TextNode* pN = GetDoc()->GetNodes().GetObject( n ); + TextPaM aPaM( n, pN->GetText().Len() ); + SetSelection( aPaM ); +} + +// ----------------------------------------------------------------------- +// TextUndoConnectParas +// ------------------------------------------------------------------------ +TextUndoConnectParas::TextUndoConnectParas( TextEngine* pTextEngine, sal_uLong nPara, sal_uInt16 nPos ) + : TextUndo( pTextEngine ) +{ + mnPara = nPara; + mnSepPos = nPos; +} + +TextUndoConnectParas::~TextUndoConnectParas() +{ +} + +void TextUndoConnectParas::Undo() +{ + TextPaM aPaM = GetTextEngine()->SplitContent( mnPara, mnSepPos ); + SetSelection( aPaM ); +} + +void TextUndoConnectParas::Redo() +{ + TextPaM aPaM = GetTextEngine()->ConnectContents( mnPara ); + SetSelection( aPaM ); +} + + +TextUndoSplitPara::TextUndoSplitPara( TextEngine* pTextEngine, sal_uLong nPara, sal_uInt16 nPos ) + : TextUndo( pTextEngine ) +{ + mnPara = nPara; + mnSepPos = nPos; +} + +TextUndoSplitPara::~TextUndoSplitPara() +{ +} + +void TextUndoSplitPara::Undo() +{ + TextPaM aPaM = GetTextEngine()->ConnectContents( mnPara ); + SetSelection( aPaM ); +} + +void TextUndoSplitPara::Redo() +{ + TextPaM aPaM = GetTextEngine()->SplitContent( mnPara, mnSepPos ); + SetSelection( aPaM ); +} + + +TextUndoInsertChars::TextUndoInsertChars( TextEngine* pTextEngine, const TextPaM& rTextPaM, const XubString& rStr ) + : TextUndo( pTextEngine ), + maTextPaM( rTextPaM ), maText( rStr ) +{ +} + +void TextUndoInsertChars::Undo() +{ + TextSelection aSel( maTextPaM, maTextPaM ); + aSel.GetEnd().GetIndex() = aSel.GetEnd().GetIndex() + maText.Len(); + TextPaM aPaM = GetTextEngine()->ImpDeleteText( aSel ); + SetSelection( aPaM ); +} + +void TextUndoInsertChars::Redo() +{ + TextSelection aSel( maTextPaM, maTextPaM ); + GetTextEngine()->ImpInsertText( aSel, maText ); + TextPaM aNewPaM( maTextPaM ); + aNewPaM.GetIndex() = aNewPaM.GetIndex() + maText.Len(); + SetSelection( TextSelection( aSel.GetStart(), aNewPaM ) ); +} + +sal_Bool TextUndoInsertChars::Merge( SfxUndoAction* pNextAction ) +{ + if ( !pNextAction->ISA( TextUndoInsertChars ) ) + return sal_False; + + TextUndoInsertChars* pNext = (TextUndoInsertChars*)pNextAction; + + if ( maTextPaM.GetPara() != pNext->maTextPaM.GetPara() ) + return sal_False; + + if ( ( maTextPaM.GetIndex() + maText.Len() ) == pNext->maTextPaM.GetIndex() ) + { + maText += pNext->maText; + return sal_True; + } + return sal_False; +} + + +TextUndoRemoveChars::TextUndoRemoveChars( TextEngine* pTextEngine, const TextPaM& rTextPaM, const XubString& rStr ) + : TextUndo( pTextEngine ), + maTextPaM( rTextPaM ), maText( rStr ) +{ +} + +void TextUndoRemoveChars::Undo() +{ + TextSelection aSel( maTextPaM, maTextPaM ); + GetTextEngine()->ImpInsertText( aSel, maText ); + aSel.GetEnd().GetIndex() = aSel.GetEnd().GetIndex() + maText.Len(); + SetSelection( aSel ); +} + +void TextUndoRemoveChars::Redo() +{ + TextSelection aSel( maTextPaM, maTextPaM ); + aSel.GetEnd().GetIndex() = aSel.GetEnd().GetIndex() + maText.Len(); + TextPaM aPaM = GetTextEngine()->ImpDeleteText( aSel ); + SetSelection( aPaM ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/edit/textundo.hxx b/vcl/source/edit/textundo.hxx new file mode 100644 index 0000000..f86f877 --- /dev/null +++ b/vcl/source/edit/textundo.hxx @@ -0,0 +1,85 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _TEXTUNDO_HXX +#define _TEXTUNDO_HXX + +#include + +class TextEngine; + +class TextUndoManager : public SfxUndoManager +{ + TextEngine* mpTextEngine; + +protected: + + void UndoRedoStart(); + void UndoRedoEnd(); + + TextView* GetView() const { return mpTextEngine->GetActiveView(); } + +public: + TextUndoManager( TextEngine* pTextEngine ); + ~TextUndoManager(); + + using SfxUndoManager::Undo; + virtual sal_Bool Undo(); + using SfxUndoManager::Redo; + virtual sal_Bool Redo(); + +}; + +class TextUndo : public SfxUndoAction +{ +private: + TextEngine* mpTextEngine; + +protected: + + TextView* GetView() const { return mpTextEngine->GetActiveView(); } + void SetSelection( const TextSelection& rSel ); + + TextDoc* GetDoc() const { return mpTextEngine->mpDoc; } + TEParaPortions* GetTEParaPortions() const { return mpTextEngine->mpTEParaPortions; } + +public: + TYPEINFO(); + TextUndo( TextEngine* pTextEngine ); + virtual ~TextUndo(); + + TextEngine* GetTextEngine() const { return mpTextEngine; } + + virtual void Undo() = 0; + virtual void Redo() = 0; + + virtual rtl::OUString GetComment() const; +}; + +#endif // _TEXTUNDO_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/edit/textview.cxx b/vcl/source/edit/textview.cxx new file mode 100644 index 0000000..045fb30 --- /dev/null +++ b/vcl/source/edit/textview.cxx @@ -0,0 +1,2378 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + + +#include + +#include + + +using namespace ::com::sun::star; + +class TETextDataObject : public ::com::sun::star::datatransfer::XTransferable, + public ::cppu::OWeakObject + +{ +private: + String maText; + SvMemoryStream maHTMLStream; + +public: + TETextDataObject( const String& rText ); + ~TETextDataObject(); + + String& GetText() { return maText; } + SvMemoryStream& GetHTMLStream() { return maHTMLStream; } + + // ::com::sun::star::uno::XInterface + ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type & rType ) throw(::com::sun::star::uno::RuntimeException); + void SAL_CALL acquire() throw() { OWeakObject::acquire(); } + void SAL_CALL release() throw() { OWeakObject::release(); } + + // ::com::sun::star::datatransfer::XTransferable + ::com::sun::star::uno::Any SAL_CALL getTransferData( const ::com::sun::star::datatransfer::DataFlavor& aFlavor ) throw(::com::sun::star::datatransfer::UnsupportedFlavorException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + ::com::sun::star::uno::Sequence< ::com::sun::star::datatransfer::DataFlavor > SAL_CALL getTransferDataFlavors( ) throw(::com::sun::star::uno::RuntimeException); + sal_Bool SAL_CALL isDataFlavorSupported( const ::com::sun::star::datatransfer::DataFlavor& aFlavor ) throw(::com::sun::star::uno::RuntimeException); +}; + +TETextDataObject::TETextDataObject( const String& rText ) : maText( rText ) +{ +} + +TETextDataObject::~TETextDataObject() +{ +} + +// uno::XInterface +uno::Any TETextDataObject::queryInterface( const uno::Type & rType ) throw(uno::RuntimeException) +{ + uno::Any aRet = ::cppu::queryInterface( rType, (static_cast< datatransfer::XTransferable* >(this)) ); + return (aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType )); +} + +// datatransfer::XTransferable +uno::Any TETextDataObject::getTransferData( const datatransfer::DataFlavor& rFlavor ) throw(datatransfer::UnsupportedFlavorException, io::IOException, uno::RuntimeException) +{ + uno::Any aAny; + + sal_uLong nT = SotExchange::GetFormat( rFlavor ); + if ( nT == SOT_FORMAT_STRING ) + { + aAny <<= (::rtl::OUString)GetText(); + } + else if ( nT == SOT_FORMATSTR_ID_HTML ) + { + GetHTMLStream().Seek( STREAM_SEEK_TO_END ); + sal_uLong nLen = GetHTMLStream().Tell(); + GetHTMLStream().Seek(0); + + uno::Sequence< sal_Int8 > aSeq( nLen ); + memcpy( aSeq.getArray(), GetHTMLStream().GetData(), nLen ); + aAny <<= aSeq; + } + else + { + throw datatransfer::UnsupportedFlavorException(); + } + return aAny; +} + +uno::Sequence< datatransfer::DataFlavor > TETextDataObject::getTransferDataFlavors( ) throw(uno::RuntimeException) +{ + GetHTMLStream().Seek( STREAM_SEEK_TO_END ); + sal_Bool bHTML = GetHTMLStream().Tell() > 0; + uno::Sequence< datatransfer::DataFlavor > aDataFlavors( bHTML ? 2 : 1 ); + SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aDataFlavors.getArray()[0] ); + if ( bHTML ) + SotExchange::GetFormatDataFlavor( SOT_FORMATSTR_ID_HTML, aDataFlavors.getArray()[1] ); + return aDataFlavors; +} + +sal_Bool TETextDataObject::isDataFlavorSupported( const datatransfer::DataFlavor& rFlavor ) throw(uno::RuntimeException) +{ + sal_uLong nT = SotExchange::GetFormat( rFlavor ); + return ( nT == SOT_FORMAT_STRING ); +} + +struct ImpTextView +{ + TextEngine* mpTextEngine; + + Window* mpWindow; + TextSelection maSelection; + Point maStartDocPos; +// TextPaM maMBDownPaM; + + Cursor* mpCursor; + + TextDDInfo* mpDDInfo; + + VirtualDevice* mpVirtDev; + + SelectionEngine* mpSelEngine; + TextSelFunctionSet* mpSelFuncSet; + + ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSourceListener > mxDnDListener; + + sal_uInt16 mnTravelXPos; + + sal_Bool mbAutoScroll : 1; + sal_Bool mbInsertMode : 1; + sal_Bool mbReadOnly : 1; + sal_Bool mbPaintSelection : 1; + sal_Bool mbAutoIndent : 1; + sal_Bool mbHighlightSelection : 1; + sal_Bool mbCursorEnabled : 1; + sal_Bool mbClickedInSelection : 1; + sal_Bool mbSupportProtectAttribute : 1; + bool mbCursorAtEndOfLine; +}; + +// ------------------------------------------------------------------------- +// (+) class TextView +// ------------------------------------------------------------------------- +TextView::TextView( TextEngine* pEng, Window* pWindow ) : + mpImpl(new ImpTextView) +{ + pWindow->EnableRTL( sal_False ); + + mpImpl->mpWindow = pWindow; + mpImpl->mpTextEngine = pEng; + mpImpl->mpVirtDev = NULL; + + mpImpl->mbPaintSelection = sal_True; + mpImpl->mbAutoScroll = sal_True; + mpImpl->mbInsertMode = sal_True; + mpImpl->mbReadOnly = sal_False; + mpImpl->mbHighlightSelection = sal_False; + mpImpl->mbAutoIndent = sal_False; + mpImpl->mbCursorEnabled = sal_True; + mpImpl->mbClickedInSelection = sal_False; + mpImpl->mbSupportProtectAttribute = sal_False; + mpImpl->mbCursorAtEndOfLine = false; +// mbInSelection = sal_False; + + mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW; + + mpImpl->mpSelFuncSet = new TextSelFunctionSet( this ); + mpImpl->mpSelEngine = new SelectionEngine( mpImpl->mpWindow, mpImpl->mpSelFuncSet ); + mpImpl->mpSelEngine->SetSelectionMode( RANGE_SELECTION ); + mpImpl->mpSelEngine->EnableDrag( sal_True ); + + mpImpl->mpCursor = new Cursor; + mpImpl->mpCursor->Show(); + pWindow->SetCursor( mpImpl->mpCursor ); + pWindow->SetInputContext( InputContext( pEng->GetFont(), INPUTCONTEXT_TEXT|INPUTCONTEXT_EXTTEXTINPUT ) ); + + if ( pWindow->GetSettings().GetStyleSettings().GetSelectionOptions() & SELECTION_OPTION_INVERT ) + mpImpl->mbHighlightSelection = sal_True; + + pWindow->SetLineColor(); + + mpImpl->mpDDInfo = NULL; + + if ( pWindow->GetDragGestureRecognizer().is() ) + { + vcl::unohelper::DragAndDropWrapper* pDnDWrapper = new vcl::unohelper::DragAndDropWrapper( this ); + mpImpl->mxDnDListener = pDnDWrapper; + + uno::Reference< datatransfer::dnd::XDragGestureListener> xDGL( mpImpl->mxDnDListener, uno::UNO_QUERY ); + pWindow->GetDragGestureRecognizer()->addDragGestureListener( xDGL ); + uno::Reference< datatransfer::dnd::XDropTargetListener> xDTL( xDGL, uno::UNO_QUERY ); + pWindow->GetDropTarget()->addDropTargetListener( xDTL ); + pWindow->GetDropTarget()->setActive( sal_True ); + pWindow->GetDropTarget()->setDefaultActions( datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE ); + } +} + +TextView::~TextView() +{ + delete mpImpl->mpSelEngine; + delete mpImpl->mpSelFuncSet; + delete mpImpl->mpVirtDev; + + if ( mpImpl->mpWindow->GetCursor() == mpImpl->mpCursor ) + mpImpl->mpWindow->SetCursor( 0 ); + delete mpImpl->mpCursor; + delete mpImpl->mpDDInfo; + delete mpImpl; +} + +void TextView::Invalidate() +{ + mpImpl->mpWindow->Invalidate(); +} + +void TextView::SetSelection( const TextSelection& rTextSel, sal_Bool bGotoCursor ) +{ + // Falls jemand gerade ein leeres Attribut hinterlassen hat, + // und dann der Outliner die Selektion manipulitert: + if ( !mpImpl->maSelection.HasRange() ) + mpImpl->mpTextEngine->CursorMoved( mpImpl->maSelection.GetStart().GetPara() ); + + // Wenn nach einem KeyInput die Selection manipuliert wird: + mpImpl->mpTextEngine->CheckIdleFormatter(); + + HideSelection(); + TextSelection aNewSel( rTextSel ); + mpImpl->mpTextEngine->ValidateSelection( aNewSel ); + ImpSetSelection( aNewSel ); + ShowSelection(); + ShowCursor( bGotoCursor ); +} + +void TextView::SetSelection( const TextSelection& rTextSel ) +{ + SetSelection( rTextSel, mpImpl->mbAutoScroll ); +} + +const TextSelection& TextView::GetSelection() const +{ + return mpImpl->maSelection; +} +TextSelection& TextView::GetSelection() +{ + return mpImpl->maSelection; +} + +void TextView::DeleteSelected() +{ +// HideSelection(); + + mpImpl->mpTextEngine->UndoActionStart(); + TextPaM aPaM = mpImpl->mpTextEngine->ImpDeleteText( mpImpl->maSelection ); + mpImpl->mpTextEngine->UndoActionEnd(); + + ImpSetSelection( aPaM ); + mpImpl->mpTextEngine->FormatAndUpdate( this ); + ShowCursor(); +} + +void TextView::ImpPaint( OutputDevice* pOut, const Point& rStartPos, Rectangle const* pPaintArea, TextSelection const* pPaintRange, TextSelection const* pSelection ) +{ + if ( !mpImpl->mbPaintSelection ) + pSelection = NULL; + else + { + // Richtige Hintergrundfarbe einstellen. + // Ich bekomme leider nicht mit, ob sich diese inzwischen geaendert hat. + Font aFont = mpImpl->mpTextEngine->GetFont(); + Color aColor = pOut->GetBackground().GetColor(); + aColor.SetTransparency( 0 ); + if ( aColor != aFont.GetFillColor() ) + { + if( aFont.IsTransparent() ) + aColor = Color( COL_TRANSPARENT ); + aFont.SetFillColor( aColor ); + mpImpl->mpTextEngine->maFont = aFont; + } + } + + mpImpl->mpTextEngine->ImpPaint( pOut, rStartPos, pPaintArea, pPaintRange, pSelection ); +} + +void TextView::Paint( const Rectangle& rRect ) +{ + ImpPaint( rRect, sal_False ); +} + +void TextView::ImpPaint( const Rectangle& rRect, sal_Bool bUseVirtDev ) +{ + if ( !mpImpl->mpTextEngine->GetUpdateMode() || mpImpl->mpTextEngine->IsInUndo() ) + return; + + TextSelection *pDrawSelection = NULL; + if ( !mpImpl->mbHighlightSelection && mpImpl->maSelection.HasRange() ) + pDrawSelection = &mpImpl->maSelection; + + if ( bUseVirtDev ) + { + VirtualDevice* pVDev = GetVirtualDevice(); + + const Color& rBackgroundColor = mpImpl->mpWindow->GetBackground().GetColor(); + if ( pVDev->GetFillColor() != rBackgroundColor ) + pVDev->SetFillColor( rBackgroundColor ); + if ( pVDev->GetBackground().GetColor() != rBackgroundColor ) + pVDev->SetBackground( rBackgroundColor ); + + sal_Bool bVDevValid = sal_True; + Size aOutSz( pVDev->GetOutputSizePixel() ); + if ( ( aOutSz.Width() < rRect.GetWidth() ) || + ( aOutSz.Height() < rRect.GetHeight() ) ) + { + bVDevValid = pVDev->SetOutputSizePixel( rRect.GetSize() ); + } + else + { + // Das VirtDev kann bei einem Resize sehr gross werden => + // irgendwann mal kleiner machen! + if ( ( aOutSz.Height() > ( rRect.GetHeight() + 20 ) ) || + ( aOutSz.Width() > ( rRect.GetWidth() + 20 ) ) ) + { + bVDevValid = pVDev->SetOutputSizePixel( rRect.GetSize() ); + } + else + { + pVDev->Erase(); + } + } + if ( !bVDevValid ) + { + ImpPaint( rRect, sal_False /* ohne VDev */ ); + return; + } + + Rectangle aTmpRec( Point( 0, 0 ), rRect.GetSize() ); + + Point aDocPos( mpImpl->maStartDocPos.X(), mpImpl->maStartDocPos.Y() + rRect.Top() ); + Point aStartPos = ImpGetOutputStartPos( aDocPos ); + ImpPaint( pVDev, aStartPos, &aTmpRec, NULL, pDrawSelection ); + mpImpl->mpWindow->DrawOutDev( rRect.TopLeft(), rRect.GetSize(), + Point(0,0), rRect.GetSize(), *pVDev ); +// ShowSelection(); + if ( mpImpl->mbHighlightSelection ) + ImpHighlight( mpImpl->maSelection ); + } + else + { + Point aStartPos = ImpGetOutputStartPos( mpImpl->maStartDocPos ); + ImpPaint( mpImpl->mpWindow, aStartPos, &rRect, NULL, pDrawSelection ); + +// ShowSelection(); + if ( mpImpl->mbHighlightSelection ) + ImpHighlight( mpImpl->maSelection ); + } +} + +void TextView::ImpHighlight( const TextSelection& rSel ) +{ + TextSelection aSel( rSel ); + aSel.Justify(); + if ( aSel.HasRange() && !mpImpl->mpTextEngine->IsInUndo() && mpImpl->mpTextEngine->GetUpdateMode() ) + { + mpImpl->mpCursor->Hide(); + + DBG_ASSERT( !mpImpl->mpTextEngine->mpIdleFormatter->IsActive(), "ImpHighlight: Not formatted!" ); + + Rectangle aVisArea( mpImpl->maStartDocPos, mpImpl->mpWindow->GetOutputSizePixel() ); + long nY = 0; + sal_uLong nStartPara = aSel.GetStart().GetPara(); + sal_uLong nEndPara = aSel.GetEnd().GetPara(); + for ( sal_uLong nPara = 0; nPara <= nEndPara; nPara++ ) + { + long nParaHeight = (long)mpImpl->mpTextEngine->CalcParaHeight( nPara ); + if ( ( nPara >= nStartPara ) && ( ( nY + nParaHeight ) > aVisArea.Top() ) ) + { + TEParaPortion* pTEParaPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( nPara ); + sal_uInt16 nStartLine = 0; + sal_uInt16 nEndLine = pTEParaPortion->GetLines().size() -1; + if ( nPara == nStartPara ) + nStartLine = pTEParaPortion->GetLineNumber( aSel.GetStart().GetIndex(), sal_False ); + if ( nPara == nEndPara ) + nEndLine = pTEParaPortion->GetLineNumber( aSel.GetEnd().GetIndex(), sal_True ); + + // ueber die Zeilen iterieren.... + for ( sal_uInt16 nLine = nStartLine; nLine <= nEndLine; nLine++ ) + { + TextLine* pLine = pTEParaPortion->GetLines()[ nLine ]; + sal_uInt16 nStartIndex = pLine->GetStart(); + sal_uInt16 nEndIndex = pLine->GetEnd(); + if ( ( nPara == nStartPara ) && ( nLine == nStartLine ) ) + nStartIndex = aSel.GetStart().GetIndex(); + if ( ( nPara == nEndPara ) && ( nLine == nEndLine ) ) + nEndIndex = aSel.GetEnd().GetIndex(); + + // Kann passieren, wenn am Anfang einer umgebrochenen Zeile. + if ( nEndIndex < nStartIndex ) + nEndIndex = nStartIndex; + + Rectangle aTmpRec( mpImpl->mpTextEngine->GetEditCursor( TextPaM( nPara, nStartIndex ), sal_False ) ); + aTmpRec.Top() += nY; + aTmpRec.Bottom() += nY; + Point aTopLeft( aTmpRec.TopLeft() ); + + aTmpRec = mpImpl->mpTextEngine->GetEditCursor( TextPaM( nPara, nEndIndex ), sal_True ); + aTmpRec.Top() += nY; + aTmpRec.Bottom() += nY; + Point aBottomRight( aTmpRec.BottomRight() ); + aBottomRight.X()--; + + // Nur Painten, wenn im sichtbaren Bereich... + if ( ( aTopLeft.X() < aBottomRight.X() ) && ( aBottomRight.Y() >= aVisArea.Top() ) ) + { + Point aPnt1( GetWindowPos( aTopLeft ) ); + Point aPnt2( GetWindowPos( aBottomRight ) ); + + Rectangle aRect( aPnt1, aPnt2 ); + mpImpl->mpWindow->Invert( aRect ); + } + } + } + nY += nParaHeight; + + if ( nY >= aVisArea.Bottom() ) + break; + } + } +} + +void TextView::ImpSetSelection( const TextSelection& rSelection ) +{ + if ( rSelection != mpImpl->maSelection ) + { + mpImpl->maSelection = rSelection; + mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_VIEWSELECTIONCHANGED ) ); + } +} + +void TextView::ShowSelection() +{ + ImpShowHideSelection( sal_True ); +} + +void TextView::HideSelection() +{ + ImpShowHideSelection( sal_False ); +} + +void TextView::ShowSelection( const TextSelection& rRange ) +{ + ImpShowHideSelection( sal_True, &rRange ); +} + +void TextView::ImpShowHideSelection( sal_Bool bShow, const TextSelection* pRange ) +{ + const TextSelection* pRangeOrSelection = pRange ? pRange : &mpImpl->maSelection; + + if ( pRangeOrSelection->HasRange() ) + { + if ( mpImpl->mbHighlightSelection ) + { + ImpHighlight( *pRangeOrSelection ); + } + else + { + if( mpImpl->mpWindow->IsPaintTransparent() ) + mpImpl->mpWindow->Invalidate(); + else + { + Rectangle aOutArea( Point( 0, 0 ), mpImpl->mpWindow->GetOutputSizePixel() ); + Point aStartPos( ImpGetOutputStartPos( mpImpl->maStartDocPos ) ); + TextSelection aRange( *pRangeOrSelection ); + aRange.Justify(); + sal_Bool bVisCursor = mpImpl->mpCursor->IsVisible(); + mpImpl->mpCursor->Hide(); + ImpPaint( mpImpl->mpWindow, aStartPos, &aOutArea, &aRange, bShow ? &mpImpl->maSelection : NULL ); + if ( bVisCursor ) + mpImpl->mpCursor->Show(); + } + } + } +} + +VirtualDevice* TextView::GetVirtualDevice() +{ + if ( !mpImpl->mpVirtDev ) + { + mpImpl->mpVirtDev = new VirtualDevice; + mpImpl->mpVirtDev->SetLineColor(); + } + return mpImpl->mpVirtDev; +} + +void TextView::EraseVirtualDevice() +{ + delete mpImpl->mpVirtDev; + mpImpl->mpVirtDev = 0; +} + +sal_Bool TextView::KeyInput( const KeyEvent& rKeyEvent ) +{ + sal_Bool bDone = sal_True; + sal_Bool bModified = sal_False; + sal_Bool bMoved = sal_False; + sal_Bool bEndKey = sal_False; // spezielle CursorPosition + sal_Bool bAllowIdle = sal_True; + + // Um zu pruefen ob durch irgendeine Aktion mModified, das lokale + // bModified wird z.B. bei Cut/Paste nicht gesetzt, weil dort an anderen + // Stellen das updaten erfolgt. + sal_Bool bWasModified = mpImpl->mpTextEngine->IsModified(); + mpImpl->mpTextEngine->SetModified( sal_False ); + + TextSelection aCurSel( mpImpl->maSelection ); + TextSelection aOldSel( aCurSel ); + + sal_uInt16 nCode = rKeyEvent.GetKeyCode().GetCode(); + KeyFuncType eFunc = rKeyEvent.GetKeyCode().GetFunction(); + if ( eFunc != KEYFUNC_DONTKNOW ) + { + switch ( eFunc ) + { + case KEYFUNC_CUT: + { + if ( !mpImpl->mbReadOnly ) + Cut(); + } + break; + case KEYFUNC_COPY: + { + Copy(); + } + break; + case KEYFUNC_PASTE: + { + if ( !mpImpl->mbReadOnly ) + Paste(); + } + break; + case KEYFUNC_UNDO: + { + if ( !mpImpl->mbReadOnly ) + Undo(); + } + break; + case KEYFUNC_REDO: + { + if ( !mpImpl->mbReadOnly ) + Redo(); + } + break; + + default: // wird dann evtl. unten bearbeitet. + eFunc = KEYFUNC_DONTKNOW; + } + } + if ( eFunc == KEYFUNC_DONTKNOW ) + { + switch ( nCode ) + { + case KEY_UP: + case KEY_DOWN: + case KEY_LEFT: + case KEY_RIGHT: + case KEY_HOME: + case KEY_END: + case KEY_PAGEUP: + case KEY_PAGEDOWN: + case com::sun::star::awt::Key::MOVE_WORD_FORWARD: + case com::sun::star::awt::Key::SELECT_WORD_FORWARD: + case com::sun::star::awt::Key::MOVE_WORD_BACKWARD: + case com::sun::star::awt::Key::SELECT_WORD_BACKWARD: + case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE: + case com::sun::star::awt::Key::MOVE_TO_END_OF_LINE: + case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE: + case com::sun::star::awt::Key::SELECT_TO_END_OF_LINE: + case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH: + case com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH: + case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH: + case com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH: + case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT: + case com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT: + case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT: + case com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT: + { + if ( ( !rKeyEvent.GetKeyCode().IsMod2() || ( nCode == KEY_LEFT ) || ( nCode == KEY_RIGHT ) ) + && !( rKeyEvent.GetKeyCode().IsMod1() && ( nCode == KEY_PAGEUP || nCode == KEY_PAGEDOWN ) ) ) + { + aCurSel = ImpMoveCursor( rKeyEvent ); + if ( aCurSel.HasRange() ) { + uno::Reference aSelection(GetWindow()->GetPrimarySelection()); + Copy( aSelection ); + } + bMoved = sal_True; + if ( nCode == KEY_END ) + bEndKey = sal_True; + } + else + bDone = sal_False; + } + break; + case KEY_BACKSPACE: + case KEY_DELETE: + case com::sun::star::awt::Key::DELETE_WORD_BACKWARD: + case com::sun::star::awt::Key::DELETE_WORD_FORWARD: + case com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_LINE: + case com::sun::star::awt::Key::DELETE_TO_END_OF_LINE: + { + if ( !mpImpl->mbReadOnly && !rKeyEvent.GetKeyCode().IsMod2() ) + { + sal_uInt8 nDel = ( nCode == KEY_DELETE ) ? DEL_RIGHT : DEL_LEFT; + sal_uInt8 nMode = rKeyEvent.GetKeyCode().IsMod1() ? DELMODE_RESTOFWORD : DELMODE_SIMPLE; + if ( ( nMode == DELMODE_RESTOFWORD ) && rKeyEvent.GetKeyCode().IsShift() ) + nMode = DELMODE_RESTOFCONTENT; + + switch( nCode ) + { + case com::sun::star::awt::Key::DELETE_WORD_BACKWARD: + nDel = DEL_LEFT; + nMode = DELMODE_RESTOFWORD; + break; + case com::sun::star::awt::Key::DELETE_WORD_FORWARD: + nDel = DEL_RIGHT; + nMode = DELMODE_RESTOFWORD; + break; + case com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_LINE: + nDel = DEL_LEFT; + nMode = DELMODE_RESTOFCONTENT; + break; + case com::sun::star::awt::Key::DELETE_TO_END_OF_LINE: + nDel = DEL_RIGHT; + nMode = DELMODE_RESTOFCONTENT; + break; + default: break; + } + + mpImpl->mpTextEngine->UndoActionStart(); + if(mpImpl->mbSupportProtectAttribute) + { + //expand selection to include all protected content - if there is any + const TextCharAttrib* pStartAttr = mpImpl->mpTextEngine->FindCharAttrib( + TextPaM(mpImpl->maSelection.GetStart().GetPara(), + mpImpl->maSelection.GetStart().GetIndex()), + TEXTATTR_PROTECTED ); + const TextCharAttrib* pEndAttr = mpImpl->mpTextEngine->FindCharAttrib( + TextPaM(mpImpl->maSelection.GetEnd().GetPara(), + mpImpl->maSelection.GetEnd().GetIndex()), + TEXTATTR_PROTECTED ); + if(pStartAttr && pStartAttr->GetStart() < mpImpl->maSelection.GetStart().GetIndex()) + { + mpImpl->maSelection.GetStart().GetIndex() = pStartAttr->GetStart(); + } + if(pEndAttr && pEndAttr->GetEnd() > mpImpl->maSelection.GetEnd().GetIndex()) + { + mpImpl->maSelection.GetEnd().GetIndex() = pEndAttr->GetEnd(); + } + } + aCurSel = ImpDelete( nDel, nMode ); + mpImpl->mpTextEngine->UndoActionEnd(); + bModified = sal_True; + bAllowIdle = sal_False; + } + else + bDone = sal_False; + } + break; + case KEY_TAB: + { + if ( !mpImpl->mbReadOnly && !rKeyEvent.GetKeyCode().IsShift() && + !rKeyEvent.GetKeyCode().IsMod1() && !rKeyEvent.GetKeyCode().IsMod2() && + ImplCheckTextLen( rtl::OUString('x') ) ) + { + aCurSel = mpImpl->mpTextEngine->ImpInsertText( aCurSel, '\t', !IsInsertMode() ); + bModified = sal_True; + } + else + bDone = sal_False; + } + break; + case KEY_RETURN: + { + // Shift-RETURN darf nicht geschluckt werden, weil dann keine + // mehrzeilige Eingabe in Dialogen/Property-Editor moeglich. + if ( !mpImpl->mbReadOnly && !rKeyEvent.GetKeyCode().IsMod1() && + !rKeyEvent.GetKeyCode().IsMod2() && ImplCheckTextLen( rtl::OUString('x') ) ) + { + mpImpl->mpTextEngine->UndoActionStart(); + aCurSel = mpImpl->mpTextEngine->ImpInsertParaBreak( aCurSel ); + if ( mpImpl->mbAutoIndent ) + { + TextNode* pPrev = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aCurSel.GetEnd().GetPara() - 1 ); + sal_uInt16 n = 0; + while ( ( n < pPrev->GetText().Len() ) && ( + ( pPrev->GetText().GetChar( n ) == ' ' ) || + ( pPrev->GetText().GetChar( n ) == '\t' ) ) ) + { + n++; + } + if ( n ) + aCurSel = mpImpl->mpTextEngine->ImpInsertText( aCurSel, pPrev->GetText().Copy( 0, n ) ); + } + mpImpl->mpTextEngine->UndoActionEnd(); + bModified = sal_True; + } + else + bDone = sal_False; + } + break; + case KEY_INSERT: + { + if ( !mpImpl->mbReadOnly ) + SetInsertMode( !IsInsertMode() ); + } + break; + default: + { + if ( TextEngine::IsSimpleCharInput( rKeyEvent ) ) + { + xub_Unicode nCharCode = rKeyEvent.GetCharCode(); + if ( !mpImpl->mbReadOnly && ImplCheckTextLen( rtl::OUString(nCharCode) ) ) // sonst trotzdem das Zeichen schlucken... + { + aCurSel = mpImpl->mpTextEngine->ImpInsertText( nCharCode, aCurSel, !IsInsertMode(), sal_True ); + bModified = sal_True; + } + } + else + bDone = sal_False; + } + } + } + + if ( aCurSel != aOldSel ) // Check if changed, maybe other method already changed mpImpl->maSelection, don't overwrite that! + ImpSetSelection( aCurSel ); + + mpImpl->mpTextEngine->UpdateSelections(); + + if ( ( nCode != KEY_UP ) && ( nCode != KEY_DOWN ) ) + mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW; + + if ( bModified ) + { + // Idle-Formatter nur, wenn AnyInput. + if ( bAllowIdle && Application::AnyInput( VCL_INPUT_KEYBOARD) ) + mpImpl->mpTextEngine->IdleFormatAndUpdate( this ); + else + mpImpl->mpTextEngine->FormatAndUpdate( this); + } + else if ( bMoved ) + { + // Selection wird jetzt gezielt in ImpMoveCursor gemalt. + ImpShowCursor( mpImpl->mbAutoScroll, sal_True, bEndKey ); + } + + if ( mpImpl->mpTextEngine->IsModified() ) + mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) ); + else if ( bWasModified ) + mpImpl->mpTextEngine->SetModified( sal_True ); + + return bDone; +} + +void TextView::MouseButtonUp( const MouseEvent& rMouseEvent ) +{ + mpImpl->mbClickedInSelection = sal_False; + mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW; + mpImpl->mpSelEngine->SelMouseButtonUp( rMouseEvent ); + if ( rMouseEvent.IsMiddle() && !IsReadOnly() && + ( GetWindow()->GetSettings().GetMouseSettings().GetMiddleButtonAction() == MOUSE_MIDDLE_PASTESELECTION ) ) + { + uno::Reference aSelection(GetWindow()->GetPrimarySelection()); + Paste( aSelection ); + if ( mpImpl->mpTextEngine->IsModified() ) + mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) ); + } + else if ( rMouseEvent.IsLeft() && GetSelection().HasRange() ) + { + uno::Reference aSelection(GetWindow()->GetPrimarySelection()); + Copy( aSelection ); + } +} + +void TextView::MouseButtonDown( const MouseEvent& rMouseEvent ) +{ + mpImpl->mpTextEngine->CheckIdleFormatter(); // Falls schnelles Tippen und MouseButtonDown + mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW; + mpImpl->mbClickedInSelection = IsSelectionAtPoint( rMouseEvent.GetPosPixel() ); + + mpImpl->mpTextEngine->SetActiveView( this ); + + mpImpl->mpSelEngine->SelMouseButtonDown( rMouseEvent ); + + // mbu 20.01.2005 - SelMouseButtonDown() possibly triggers a 'selection changed' + // notification. The appropriate handler could change the current selection, + // which is the case in the MailMerge address block control. To enable select'n'drag + // we need to reevaluate the selection after the notification has been fired. + mpImpl->mbClickedInSelection = IsSelectionAtPoint( rMouseEvent.GetPosPixel() ); + + // Sonderbehandlungen + if ( !rMouseEvent.IsShift() && ( rMouseEvent.GetClicks() >= 2 ) ) + { + if ( rMouseEvent.IsMod2() ) + { + HideSelection(); + ImpSetSelection( mpImpl->maSelection.GetEnd() ); + SetCursorAtPoint( rMouseEvent.GetPosPixel() ); // Wird von SelectionEngine bei MOD2 nicht gesetzt + } + + if ( rMouseEvent.GetClicks() == 2 ) + { + // Wort selektieren + if ( mpImpl->maSelection.GetEnd().GetIndex() < mpImpl->mpTextEngine->GetTextLen( mpImpl->maSelection.GetEnd().GetPara() ) ) + { + HideSelection(); + TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( mpImpl->maSelection.GetEnd().GetPara() ); + uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator(); + i18n::Boundary aBoundary = xBI->getWordBoundary( pNode->GetText(), mpImpl->maSelection.GetEnd().GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True ); + TextSelection aNewSel( mpImpl->maSelection ); + aNewSel.GetStart().GetIndex() = (sal_uInt16)aBoundary.startPos; + aNewSel.GetEnd().GetIndex() = (sal_uInt16)aBoundary.endPos; + if(mpImpl->mbSupportProtectAttribute) + { + //expand selection to include all protected content - if there is any + const TextCharAttrib* pStartAttr = mpImpl->mpTextEngine->FindCharAttrib( + TextPaM(aNewSel.GetStart().GetPara(), + (sal_uInt16)aBoundary.startPos), + TEXTATTR_PROTECTED ); + const TextCharAttrib* pEndAttr = mpImpl->mpTextEngine->FindCharAttrib( + TextPaM(aNewSel.GetEnd().GetPara(), + (sal_uInt16)aBoundary.endPos), + TEXTATTR_PROTECTED ); + if(pStartAttr && pStartAttr->GetStart() < aNewSel.GetStart().GetIndex()) + { + aNewSel.GetStart().GetIndex() = pStartAttr->GetStart(); + } + if(pEndAttr && pEndAttr->GetEnd() > aNewSel.GetEnd().GetIndex()) + { + aNewSel.GetEnd().GetIndex() = pEndAttr->GetEnd(); + } + } + ImpSetSelection( aNewSel ); + ShowSelection(); + ShowCursor( sal_True, sal_True ); + } + } + else if ( rMouseEvent.GetClicks() == 3 ) + { + // Absatz selektieren + if ( mpImpl->maSelection.GetStart().GetIndex() || ( mpImpl->maSelection.GetEnd().GetIndex() < mpImpl->mpTextEngine->GetTextLen( mpImpl->maSelection.GetEnd().GetPara() ) ) ) + { + HideSelection(); + TextSelection aNewSel( mpImpl->maSelection ); + aNewSel.GetStart().GetIndex() = 0; + aNewSel.GetEnd().GetIndex() = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( mpImpl->maSelection.GetEnd().GetPara() )->GetText().Len(); + ImpSetSelection( aNewSel ); + ShowSelection(); + ShowCursor( sal_True, sal_True ); + } + } + } +} + + +void TextView::MouseMove( const MouseEvent& rMouseEvent ) +{ + mpImpl->mnTravelXPos = TRAVEL_X_DONTKNOW; + mpImpl->mpSelEngine->SelMouseMove( rMouseEvent ); +} + +void TextView::Command( const CommandEvent& rCEvt ) +{ + mpImpl->mpTextEngine->CheckIdleFormatter(); // Falls schnelles Tippen und MouseButtonDown + mpImpl->mpTextEngine->SetActiveView( this ); + + if ( rCEvt.GetCommand() == COMMAND_STARTEXTTEXTINPUT ) + { + DeleteSelected(); + delete mpImpl->mpTextEngine->mpIMEInfos; + TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( GetSelection().GetEnd().GetPara() ); + mpImpl->mpTextEngine->mpIMEInfos = new TEIMEInfos( GetSelection().GetEnd(), pNode->GetText().Copy( GetSelection().GetEnd().GetIndex() ) ); + mpImpl->mpTextEngine->mpIMEInfos->bWasCursorOverwrite = !IsInsertMode(); + } + else if ( rCEvt.GetCommand() == COMMAND_ENDEXTTEXTINPUT ) + { + DBG_ASSERT( mpImpl->mpTextEngine->mpIMEInfos, "COMMAND_ENDEXTTEXTINPUT => Kein Start ?" ); + if( mpImpl->mpTextEngine->mpIMEInfos ) + { + TEParaPortion* pPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetPara() ); + pPortion->MarkSelectionInvalid( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetIndex(), 0 ); + + sal_Bool bInsertMode = !mpImpl->mpTextEngine->mpIMEInfos->bWasCursorOverwrite; + + delete mpImpl->mpTextEngine->mpIMEInfos; + mpImpl->mpTextEngine->mpIMEInfos = NULL; + + mpImpl->mpTextEngine->FormatAndUpdate( this ); + + SetInsertMode( bInsertMode ); + + if ( mpImpl->mpTextEngine->IsModified() ) + mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) ); + } + } + else if ( rCEvt.GetCommand() == COMMAND_EXTTEXTINPUT ) + { + DBG_ASSERT( mpImpl->mpTextEngine->mpIMEInfos, "COMMAND_EXTTEXTINPUT => Kein Start ?" ); + if( mpImpl->mpTextEngine->mpIMEInfos ) + { + const CommandExtTextInputData* pData = rCEvt.GetExtTextInputData(); + + if ( !pData->IsOnlyCursorChanged() ) + { + TextSelection aSelect( mpImpl->mpTextEngine->mpIMEInfos->aPos ); + aSelect.GetEnd().GetIndex() = aSelect.GetEnd().GetIndex() + mpImpl->mpTextEngine->mpIMEInfos->nLen; + aSelect = mpImpl->mpTextEngine->ImpDeleteText( aSelect ); + aSelect = mpImpl->mpTextEngine->ImpInsertText( aSelect, pData->GetText() ); + + if ( mpImpl->mpTextEngine->mpIMEInfos->bWasCursorOverwrite ) + { + sal_uInt16 nOldIMETextLen = mpImpl->mpTextEngine->mpIMEInfos->nLen; + sal_uInt16 nNewIMETextLen = pData->GetText().Len(); + + if ( ( nOldIMETextLen > nNewIMETextLen ) && + ( nNewIMETextLen < mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.Len() ) ) + { + // restore old characters + sal_uInt16 nRestore = nOldIMETextLen - nNewIMETextLen; + TextPaM aPaM( mpImpl->mpTextEngine->mpIMEInfos->aPos ); + aPaM.GetIndex() = aPaM.GetIndex() + nNewIMETextLen; + mpImpl->mpTextEngine->ImpInsertText( aPaM, mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.Copy( nNewIMETextLen, nRestore ) ); + } + else if ( ( nOldIMETextLen < nNewIMETextLen ) && + ( nOldIMETextLen < mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.Len() ) ) + { + // overwrite + sal_uInt16 nOverwrite = nNewIMETextLen - nOldIMETextLen; + if ( ( nOldIMETextLen + nOverwrite ) > mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.Len() ) + nOverwrite = mpImpl->mpTextEngine->mpIMEInfos->aOldTextAfterStartPos.Len() - nOldIMETextLen; + DBG_ASSERT( nOverwrite && (nOverwrite < 0xFF00), "IME Overwrite?!" ); + TextPaM aPaM( mpImpl->mpTextEngine->mpIMEInfos->aPos ); + aPaM.GetIndex() = aPaM.GetIndex() + nNewIMETextLen; + TextSelection aSel( aPaM ); + aSel.GetEnd().GetIndex() = + aSel.GetEnd().GetIndex() + nOverwrite; + mpImpl->mpTextEngine->ImpDeleteText( aSel ); + } + } + + if ( pData->GetTextAttr() ) + { + mpImpl->mpTextEngine->mpIMEInfos->CopyAttribs( pData->GetTextAttr(), pData->GetText().Len() ); + mpImpl->mpTextEngine->mpIMEInfos->bCursor = pData->IsCursorVisible(); + } + else + { + mpImpl->mpTextEngine->mpIMEInfos->DestroyAttribs(); + } + + TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetPara() ); + pPPortion->MarkSelectionInvalid( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetIndex(), 0 ); + mpImpl->mpTextEngine->FormatAndUpdate( this ); + } + + TextSelection aNewSel = TextPaM( mpImpl->mpTextEngine->mpIMEInfos->aPos.GetPara(), mpImpl->mpTextEngine->mpIMEInfos->aPos.GetIndex()+pData->GetCursorPos() ); + SetSelection( aNewSel ); + SetInsertMode( !pData->IsCursorOverwrite() ); + + if ( pData->IsCursorVisible() ) + ShowCursor(); + else + HideCursor(); + } + } + else if ( rCEvt.GetCommand() == COMMAND_CURSORPOS ) + { + if ( mpImpl->mpTextEngine->mpIMEInfos && mpImpl->mpTextEngine->mpIMEInfos->nLen ) + { + TextPaM aPaM( GetSelection().GetEnd() ); + Rectangle aR1 = mpImpl->mpTextEngine->PaMtoEditCursor( aPaM ); + + sal_uInt16 nInputEnd = mpImpl->mpTextEngine->mpIMEInfos->aPos.GetIndex() + mpImpl->mpTextEngine->mpIMEInfos->nLen; + + if ( !mpImpl->mpTextEngine->IsFormatted() ) + mpImpl->mpTextEngine->FormatDoc(); + + TEParaPortion* pParaPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() ); + sal_uInt16 nLine = pParaPortion->GetLineNumber( aPaM.GetIndex(), sal_True ); + TextLine* pLine = pParaPortion->GetLines()[ nLine ]; + if ( pLine && ( nInputEnd > pLine->GetEnd() ) ) + nInputEnd = pLine->GetEnd(); + Rectangle aR2 = mpImpl->mpTextEngine->PaMtoEditCursor( TextPaM( aPaM.GetPara(), nInputEnd ) ); + + long nWidth = aR2.Left()-aR1.Right(); + aR1.Move( -GetStartDocPos().X(), -GetStartDocPos().Y() ); + GetWindow()->SetCursorRect( &aR1, nWidth ); + } + else + { + GetWindow()->SetCursorRect(); + } + } + else + { + mpImpl->mpSelEngine->Command( rCEvt ); + } +} + +void TextView::ShowCursor( sal_Bool bGotoCursor, sal_Bool bForceVisCursor ) +{ + // Die Einstellung hat mehr Gewicht: + if ( !mpImpl->mbAutoScroll ) + bGotoCursor = sal_False; + ImpShowCursor( bGotoCursor, bForceVisCursor, sal_False ); +} + +void TextView::HideCursor() +{ + mpImpl->mpCursor->Hide(); +} + +void TextView::Scroll( long ndX, long ndY ) +{ + DBG_ASSERT( mpImpl->mpTextEngine->IsFormatted(), "Scroll: Nicht formatiert!" ); + + if ( !ndX && !ndY ) + return; + + Point aNewStartPos( mpImpl->maStartDocPos ); + + // Vertical: + aNewStartPos.Y() -= ndY; + if ( aNewStartPos.Y() < 0 ) + aNewStartPos.Y() = 0; + + // Horizontal: + aNewStartPos.X() -= ndX; + if ( aNewStartPos.X() < 0 ) + aNewStartPos.X() = 0; + + long nDiffX = mpImpl->maStartDocPos.X() - aNewStartPos.X(); + long nDiffY = mpImpl->maStartDocPos.Y() - aNewStartPos.Y(); + + if ( nDiffX || nDiffY ) + { + sal_Bool bVisCursor = mpImpl->mpCursor->IsVisible(); + mpImpl->mpCursor->Hide(); + mpImpl->mpWindow->Update(); + mpImpl->maStartDocPos = aNewStartPos; + + if ( mpImpl->mpTextEngine->IsRightToLeft() ) + nDiffX = -nDiffX; + mpImpl->mpWindow->Scroll( nDiffX, nDiffY ); + mpImpl->mpWindow->Update(); + mpImpl->mpCursor->SetPos( mpImpl->mpCursor->GetPos() + Point( nDiffX, nDiffY ) ); + if ( bVisCursor && !mpImpl->mbReadOnly ) + mpImpl->mpCursor->Show(); + } + + mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_VIEWSCROLLED ) ); +} + +void TextView::Undo() +{ + mpImpl->mpTextEngine->SetActiveView( this ); + mpImpl->mpTextEngine->GetUndoManager().Undo(); +} + +void TextView::Redo() +{ + mpImpl->mpTextEngine->SetActiveView( this ); + mpImpl->mpTextEngine->GetUndoManager().Redo(); +} + +void TextView::Cut() +{ + mpImpl->mpTextEngine->UndoActionStart(); + Copy(); + DeleteSelected(); + mpImpl->mpTextEngine->UndoActionEnd(); +} + +void TextView::Copy( uno::Reference< datatransfer::clipboard::XClipboard >& rxClipboard ) +{ + if ( rxClipboard.is() ) + { + TETextDataObject* pDataObj = new TETextDataObject( GetSelected() ); + + if ( mpImpl->mpTextEngine->HasAttrib( TEXTATTR_HYPERLINK ) ) // Dann auch als HTML + mpImpl->mpTextEngine->Write( pDataObj->GetHTMLStream(), &mpImpl->maSelection, sal_True ); + + const sal_uInt32 nRef = Application::ReleaseSolarMutex(); + + try + { + rxClipboard->setContents( pDataObj, NULL ); + + uno::Reference< datatransfer::clipboard::XFlushableClipboard > xFlushableClipboard( rxClipboard, uno::UNO_QUERY ); + if( xFlushableClipboard.is() ) + xFlushableClipboard->flushClipboard(); + } + catch( const ::com::sun::star::uno::Exception& ) + { + } + + Application::AcquireSolarMutex( nRef ); + } +} + +void TextView::Copy() +{ + uno::Reference aClipboard(GetWindow()->GetClipboard()); + Copy( aClipboard ); +} + +void TextView::Paste( uno::Reference< datatransfer::clipboard::XClipboard >& rxClipboard ) +{ + if ( rxClipboard.is() ) + { + uno::Reference< datatransfer::XTransferable > xDataObj; + + const sal_uInt32 nRef = Application::ReleaseSolarMutex(); + + try + { + xDataObj = rxClipboard->getContents(); + } + catch( const ::com::sun::star::uno::Exception& ) + { + } + + Application::AcquireSolarMutex( nRef ); + + if ( xDataObj.is() ) + { + datatransfer::DataFlavor aFlavor; + SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor ); + if ( xDataObj->isDataFlavorSupported( aFlavor ) ) + { + try + { + uno::Any aData = xDataObj->getTransferData( aFlavor ); + ::rtl::OUString aText; + aData >>= aText; + bool bWasTruncated = false; + if( mpImpl->mpTextEngine->GetMaxTextLen() != 0 ) + bWasTruncated = ImplTruncateNewText( aText ); + InsertNewText( aText, sal_False ); + mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) ); + + if( bWasTruncated ) + Edit::ShowTruncationWarning( mpImpl->mpWindow ); + } + catch( const ::com::sun::star::datatransfer::UnsupportedFlavorException& ) + { + } + } + } + } +} + +void TextView::Paste() +{ + uno::Reference aClipboard(GetWindow()->GetClipboard()); + Paste( aClipboard ); +} + +String TextView::GetSelected() +{ + return GetSelected( GetSystemLineEnd() ); +} + +String TextView::GetSelected( LineEnd aSeparator ) +{ + return mpImpl->mpTextEngine->GetText( mpImpl->maSelection, aSeparator ); +} + +void TextView::SetInsertMode( sal_Bool bInsert ) +{ + if ( mpImpl->mbInsertMode != bInsert ) + { + mpImpl->mbInsertMode = bInsert; + ShowCursor( mpImpl->mbAutoScroll, sal_False ); + } +} + +void TextView::SetReadOnly( sal_Bool bReadOnly ) +{ + if ( mpImpl->mbReadOnly != bReadOnly ) + { + mpImpl->mbReadOnly = bReadOnly; + if ( !mpImpl->mbReadOnly ) + ShowCursor( mpImpl->mbAutoScroll, sal_False ); + else + HideCursor(); + + GetWindow()->SetInputContext( InputContext( mpImpl->mpTextEngine->GetFont(), bReadOnly ? INPUTCONTEXT_TEXT|INPUTCONTEXT_EXTTEXTINPUT : 0 ) ); + } +} + +TextSelection TextView::ImpMoveCursor( const KeyEvent& rKeyEvent ) +{ + // Eigentlich nur bei Up/Down noetig, aber was solls. + mpImpl->mpTextEngine->CheckIdleFormatter(); + + TextPaM aPaM( mpImpl->maSelection.GetEnd() ); + TextPaM aOldEnd( aPaM ); + + TextDirectionality eTextDirection = TextDirectionality_LeftToRight_TopToBottom; + if ( mpImpl->mpTextEngine->IsRightToLeft() ) + eTextDirection = TextDirectionality_RightToLeft_TopToBottom; + + KeyEvent aTranslatedKeyEvent = rKeyEvent.LogicalTextDirectionality( eTextDirection ); + + sal_Bool bCtrl = aTranslatedKeyEvent.GetKeyCode().IsMod1() ? sal_True : sal_False; + sal_uInt16 nCode = aTranslatedKeyEvent.GetKeyCode().GetCode(); + + bool bSelect = aTranslatedKeyEvent.GetKeyCode().IsShift(); + switch ( nCode ) + { + case KEY_UP: aPaM = CursorUp( aPaM ); + break; + case KEY_DOWN: aPaM = CursorDown( aPaM ); + break; + case KEY_HOME: aPaM = bCtrl ? CursorStartOfDoc() : CursorStartOfLine( aPaM ); + break; + case KEY_END: aPaM = bCtrl ? CursorEndOfDoc() : CursorEndOfLine( aPaM ); + break; + case KEY_PAGEUP: aPaM = bCtrl ? CursorStartOfDoc() : PageUp( aPaM ); + break; + case KEY_PAGEDOWN: aPaM = bCtrl ? CursorEndOfDoc() : PageDown( aPaM ); + break; + case KEY_LEFT: aPaM = bCtrl ? CursorWordLeft( aPaM ) : CursorLeft( aPaM, aTranslatedKeyEvent.GetKeyCode().IsMod2() ? (sal_uInt16)i18n::CharacterIteratorMode::SKIPCHARACTER : (sal_uInt16)i18n::CharacterIteratorMode::SKIPCELL ); + break; + case KEY_RIGHT: aPaM = bCtrl ? CursorWordRight( aPaM ) : CursorRight( aPaM, aTranslatedKeyEvent.GetKeyCode().IsMod2() ? (sal_uInt16)i18n::CharacterIteratorMode::SKIPCHARACTER : (sal_uInt16)i18n::CharacterIteratorMode::SKIPCELL ); + break; + case com::sun::star::awt::Key::SELECT_WORD_FORWARD: + bSelect = true; // fallthrough intentional + case com::sun::star::awt::Key::MOVE_WORD_FORWARD: + aPaM = CursorWordRight( aPaM ); + break; + case com::sun::star::awt::Key::SELECT_WORD_BACKWARD: + bSelect = true; // fallthrough intentional + case com::sun::star::awt::Key::MOVE_WORD_BACKWARD: + aPaM = CursorWordLeft( aPaM ); + break; + case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE: + bSelect = true; // fallthrough intentional + case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE: + aPaM = CursorStartOfLine( aPaM ); + break; + case com::sun::star::awt::Key::SELECT_TO_END_OF_LINE: + bSelect = true; // fallthrough intentional + case com::sun::star::awt::Key::MOVE_TO_END_OF_LINE: + aPaM = CursorEndOfLine( aPaM ); + break; + case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH: + bSelect = true; // falltthrough intentional + case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH: + aPaM = CursorStartOfParagraph( aPaM ); + break; + case com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH: + bSelect = true; // falltthrough intentional + case com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH: + aPaM = CursorEndOfParagraph( aPaM ); + break; + case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT: + bSelect = true; // falltthrough intentional + case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT: + aPaM = CursorStartOfDoc(); + break; + case com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT: + bSelect = true; // falltthrough intentional + case com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT: + aPaM = CursorEndOfDoc(); + break; + } + + // Bewirkt evtl. ein CreateAnchor oder Deselection all + mpImpl->mpSelEngine->CursorPosChanging( bSelect, aTranslatedKeyEvent.GetKeyCode().IsMod1() ); + + if ( aOldEnd != aPaM ) + { + mpImpl->mpTextEngine->CursorMoved( aOldEnd.GetPara() ); + + TextSelection aNewSelection( mpImpl->maSelection ); + aNewSelection.GetEnd() = aPaM; + if ( bSelect ) + { + // Dann wird die Selektion erweitert... + ImpSetSelection( aNewSelection ); + ShowSelection( TextSelection( aOldEnd, aPaM ) ); + } + else + { + aNewSelection.GetStart() = aPaM; + ImpSetSelection( aNewSelection ); + } + } + + return mpImpl->maSelection; +} + +void TextView::InsertText( const XubString& rStr, sal_Bool bSelect ) +{ + InsertNewText( rStr, bSelect ); +} + +void TextView::InsertNewText( const rtl::OUString& rStr, sal_Bool bSelect ) +{ +// HideSelection(); + mpImpl->mpTextEngine->UndoActionStart(); + + /* #i87633# + break inserted text into chunks that fit into the underlying String + based API (which has a maximum length of 65534 elements + + note: this will of course still cause problems for lines longer than those + 65534 elements, but those cases will hopefully be few. + In the long run someone should switch the TextEngine to OUString instead of String + */ + sal_Int32 nLen = rStr.getLength(); + sal_Int32 nPos = 0; + do + { + sal_Int32 nChunkLen = nLen > 65534 ? 65534 : nLen; + String aChunk( rStr.copy( nPos, nChunkLen ) ); + + TextSelection aNewSel( mpImpl->maSelection ); + + TextPaM aPaM = mpImpl->mpTextEngine->ImpInsertText( mpImpl->maSelection, aChunk ); + + if ( bSelect ) + { + aNewSel.Justify(); + aNewSel.GetEnd() = aPaM; + } + else + { + aNewSel = aPaM; + } + + ImpSetSelection( aNewSel ); + nLen -= nChunkLen; + nPos += nChunkLen; + } + while( nLen ); + + mpImpl->mpTextEngine->UndoActionEnd(); + + mpImpl->mpTextEngine->FormatAndUpdate( this ); +} + +TextPaM TextView::CursorLeft( const TextPaM& rPaM, sal_uInt16 nCharacterIteratorMode ) +{ + TextPaM aPaM( rPaM ); + + if ( aPaM.GetIndex() ) + { + TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() ); + uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator(); + sal_Int32 nCount = 1; + aPaM.GetIndex() = (sal_uInt16)xBI->previousCharacters( pNode->GetText(), aPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), nCharacterIteratorMode, nCount, nCount ); + } + else if ( aPaM.GetPara() ) + { + aPaM.GetPara()--; + TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() ); + aPaM.GetIndex() = pNode->GetText().Len(); + } + return aPaM; +} + +TextPaM TextView::CursorRight( const TextPaM& rPaM, sal_uInt16 nCharacterIteratorMode ) +{ + TextPaM aPaM( rPaM ); + + TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() ); + if ( aPaM.GetIndex() < pNode->GetText().Len() ) + { + uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator(); + sal_Int32 nCount = 1; + aPaM.GetIndex() = (sal_uInt16)xBI->nextCharacters( pNode->GetText(), aPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), nCharacterIteratorMode, nCount, nCount ); + } + else if ( aPaM.GetPara() < ( mpImpl->mpTextEngine->mpDoc->GetNodes().Count()-1) ) + { + aPaM.GetPara()++; + aPaM.GetIndex() = 0; + } + + return aPaM; +} + + +TextPaM TextView::CursorWordLeft( const TextPaM& rPaM ) +{ + TextPaM aPaM( rPaM ); + + if ( aPaM.GetIndex() ) + { + TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() ); + uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator(); + i18n::Boundary aBoundary = xBI->getWordBoundary( pNode->GetText(), rPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True ); + if ( aBoundary.startPos >= rPaM.GetIndex() ) + aBoundary = xBI->previousWord( pNode->GetText(), rPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES ); + aPaM.GetIndex() = ( aBoundary.startPos != -1 ) ? (sal_uInt16)aBoundary.startPos : 0; + } + else if ( aPaM.GetPara() ) + { + aPaM.GetPara()--; + TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() ); + aPaM.GetIndex() = pNode->GetText().Len(); + } + return aPaM; +} + + +TextPaM TextView::CursorWordRight( const TextPaM& rPaM ) +{ + TextPaM aPaM( rPaM ); + + TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() ); + if ( aPaM.GetIndex() < pNode->GetText().Len() ) + { + uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator(); + i18n::Boundary aBoundary = xBI->nextWord( pNode->GetText(), aPaM.GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES ); + aPaM.GetIndex() = (sal_uInt16)aBoundary.startPos; + } + else if ( aPaM.GetPara() < ( mpImpl->mpTextEngine->mpDoc->GetNodes().Count()-1) ) + { + aPaM.GetPara()++; + aPaM.GetIndex() = 0; + } + + return aPaM; +} + +TextPaM TextView::ImpDelete( sal_uInt8 nMode, sal_uInt8 nDelMode ) +{ + if ( mpImpl->maSelection.HasRange() ) // dann nur Sel. loeschen + return mpImpl->mpTextEngine->ImpDeleteText( mpImpl->maSelection ); + + TextPaM aStartPaM = mpImpl->maSelection.GetStart(); + TextPaM aEndPaM = aStartPaM; + if ( nMode == DEL_LEFT ) + { + if ( nDelMode == DELMODE_SIMPLE ) + { + aEndPaM = CursorLeft( aEndPaM, (sal_uInt16)i18n::CharacterIteratorMode::SKIPCHARACTER ); + } + else if ( nDelMode == DELMODE_RESTOFWORD ) + { + TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aEndPaM.GetPara() ); + uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator(); + i18n::Boundary aBoundary = xBI->getWordBoundary( pNode->GetText(), mpImpl->maSelection.GetEnd().GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True ); + if ( aBoundary.startPos == mpImpl->maSelection.GetEnd().GetIndex() ) + aBoundary = xBI->previousWord( pNode->GetText(), mpImpl->maSelection.GetEnd().GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES ); + // #i63506# startPos is -1 when the paragraph starts with a tab + aEndPaM.GetIndex() = (aBoundary.startPos >= 0) ? (sal_uInt16)aBoundary.startPos : 0; + } + else // DELMODE_RESTOFCONTENT + { + if ( aEndPaM.GetIndex() != 0 ) + aEndPaM.GetIndex() = 0; + else if ( aEndPaM.GetPara() ) + { + // Absatz davor + aEndPaM.GetPara()--; + aEndPaM.GetIndex() = 0; + } + } + } + else + { + if ( nDelMode == DELMODE_SIMPLE ) + { + aEndPaM = CursorRight( aEndPaM, (sal_uInt16)i18n::CharacterIteratorMode::SKIPCELL ); + } + else if ( nDelMode == DELMODE_RESTOFWORD ) + { + TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aEndPaM.GetPara() ); + uno::Reference < i18n::XBreakIterator > xBI = mpImpl->mpTextEngine->GetBreakIterator(); + i18n::Boundary aBoundary = xBI->nextWord( pNode->GetText(), mpImpl->maSelection.GetEnd().GetIndex(), mpImpl->mpTextEngine->GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES ); + aEndPaM.GetIndex() = (sal_uInt16)aBoundary.startPos; + } + else // DELMODE_RESTOFCONTENT + { + TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aEndPaM.GetPara() ); + if ( aEndPaM.GetIndex() < pNode->GetText().Len() ) + aEndPaM.GetIndex() = pNode->GetText().Len(); + else if ( aEndPaM.GetPara() < ( mpImpl->mpTextEngine->mpDoc->GetNodes().Count() - 1 ) ) + { + // Absatz danach + aEndPaM.GetPara()++; + TextNode* pNextNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aEndPaM.GetPara() ); + aEndPaM.GetIndex() = pNextNode->GetText().Len(); + } + } + } + + return mpImpl->mpTextEngine->ImpDeleteText( TextSelection( aStartPaM, aEndPaM ) ); +} + + + +TextPaM TextView::CursorUp( const TextPaM& rPaM ) +{ + TextPaM aPaM( rPaM ); + + long nX; + if ( mpImpl->mnTravelXPos == TRAVEL_X_DONTKNOW ) + { + nX = mpImpl->mpTextEngine->GetEditCursor( rPaM, sal_False ).Left(); + mpImpl->mnTravelXPos = (sal_uInt16)nX+1; + } + else + nX = mpImpl->mnTravelXPos; + + TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() ); + sal_uInt16 nLine = pPPortion->GetLineNumber( rPaM.GetIndex(), sal_False ); + if ( nLine ) // gleicher Absatz + { + sal_uInt16 nCharPos = mpImpl->mpTextEngine->GetCharPos( rPaM.GetPara(), nLine-1, nX ); + aPaM.GetIndex() = nCharPos; + // Wenn davor eine autom.Umgebrochene Zeile, und ich muss genau an das + // Ende dieser Zeile, landet der Cursor in der aktuellen Zeile am Anfang + // Siehe Problem: Letztes Zeichen einer autom.umgebr. Zeile = Cursor + TextLine* pLine = pPPortion->GetLines()[ nLine - 1 ]; + if ( aPaM.GetIndex() && ( aPaM.GetIndex() == pLine->GetEnd() ) ) + aPaM.GetIndex()--; + } + else if ( rPaM.GetPara() ) // vorheriger Absatz + { + aPaM.GetPara()--; + pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() ); + sal_uInt16 nL = pPPortion->GetLines().size() - 1; + sal_uInt16 nCharPos = mpImpl->mpTextEngine->GetCharPos( aPaM.GetPara(), nL, nX+1 ); + aPaM.GetIndex() = nCharPos; + } + + return aPaM; +} + +TextPaM TextView::CursorDown( const TextPaM& rPaM ) +{ + TextPaM aPaM( rPaM ); + + long nX; + if ( mpImpl->mnTravelXPos == TRAVEL_X_DONTKNOW ) + { + nX = mpImpl->mpTextEngine->GetEditCursor( rPaM, sal_False ).Left(); + mpImpl->mnTravelXPos = (sal_uInt16)nX+1; + } + else + nX = mpImpl->mnTravelXPos; + + TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() ); + sal_uInt16 nLine = pPPortion->GetLineNumber( rPaM.GetIndex(), sal_False ); + if ( nLine < ( pPPortion->GetLines().size() - 1 ) ) + { + sal_uInt16 nCharPos = mpImpl->mpTextEngine->GetCharPos( rPaM.GetPara(), nLine+1, nX ); + aPaM.GetIndex() = nCharPos; + + // Sonderbehandlung siehe CursorUp... + TextLine* pLine = pPPortion->GetLines()[ nLine + 1 ]; + if ( ( aPaM.GetIndex() == pLine->GetEnd() ) && ( aPaM.GetIndex() > pLine->GetStart() ) && aPaM.GetIndex() < pPPortion->GetNode()->GetText().Len() ) + aPaM.GetIndex()--; + } + else if ( rPaM.GetPara() < ( mpImpl->mpTextEngine->mpDoc->GetNodes().Count() - 1 ) ) // naechster Absatz + { + aPaM.GetPara()++; + pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() ); + sal_uInt16 nCharPos = mpImpl->mpTextEngine->GetCharPos( aPaM.GetPara(), 0, nX+1 ); + aPaM.GetIndex() = nCharPos; + TextLine* pLine = pPPortion->GetLines().front(); + if ( ( aPaM.GetIndex() == pLine->GetEnd() ) && ( aPaM.GetIndex() > pLine->GetStart() ) && ( pPPortion->GetLines().size() > 1 ) ) + aPaM.GetIndex()--; + } + + return aPaM; +} + +TextPaM TextView::CursorStartOfLine( const TextPaM& rPaM ) +{ + TextPaM aPaM( rPaM ); + + TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() ); + sal_uInt16 nLine = pPPortion->GetLineNumber( aPaM.GetIndex(), sal_False ); + TextLine* pLine = pPPortion->GetLines()[ nLine ]; + aPaM.GetIndex() = pLine->GetStart(); + + return aPaM; +} + +TextPaM TextView::CursorEndOfLine( const TextPaM& rPaM ) +{ + TextPaM aPaM( rPaM ); + + TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( rPaM.GetPara() ); + sal_uInt16 nLine = pPPortion->GetLineNumber( aPaM.GetIndex(), sal_False ); + TextLine* pLine = pPPortion->GetLines()[ nLine ]; + aPaM.GetIndex() = pLine->GetEnd(); + + if ( pLine->GetEnd() > pLine->GetStart() ) // Leerzeile + { + xub_Unicode cLastChar = pPPortion->GetNode()->GetText().GetChar((sal_uInt16)(aPaM.GetIndex()-1) ); + if ( ( cLastChar == ' ' ) && ( aPaM.GetIndex() != pPPortion->GetNode()->GetText().Len() ) ) + { + // Bei einem Blank in einer autom. umgebrochenen Zeile macht es Sinn, + // davor zu stehen, da der Anwender hinter das Wort will. + // Wenn diese geaendert wird, Sonderbehandlung fuer Pos1 nach End! + aPaM.GetIndex()--; + } + } + return aPaM; +} + +TextPaM TextView::CursorStartOfParagraph( const TextPaM& rPaM ) +{ + TextPaM aPaM( rPaM ); + aPaM.GetIndex() = 0; + return aPaM; +} + +TextPaM TextView::CursorEndOfParagraph( const TextPaM& rPaM ) +{ + TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( rPaM.GetPara() ); + TextPaM aPaM( rPaM ); + aPaM.GetIndex() = pNode->GetText().Len(); + return aPaM; +} + +TextPaM TextView::CursorStartOfDoc() +{ + TextPaM aPaM( 0, 0 ); + return aPaM; +} + +TextPaM TextView::CursorEndOfDoc() +{ + sal_uLong nNode = mpImpl->mpTextEngine->mpDoc->GetNodes().Count() - 1; + TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( nNode ); + TextPaM aPaM( nNode, pNode->GetText().Len() ); + return aPaM; +} + +TextPaM TextView::PageUp( const TextPaM& rPaM ) +{ + Rectangle aRec = mpImpl->mpTextEngine->PaMtoEditCursor( rPaM ); + Point aTopLeft = aRec.TopLeft(); + aTopLeft.Y() -= mpImpl->mpWindow->GetOutputSizePixel().Height() * 9/10; + aTopLeft.X() += 1; + if ( aTopLeft.Y() < 0 ) + aTopLeft.Y() = 0; + + TextPaM aPaM = mpImpl->mpTextEngine->GetPaM( aTopLeft ); + return aPaM; +} + +TextPaM TextView::PageDown( const TextPaM& rPaM ) +{ + Rectangle aRec = mpImpl->mpTextEngine->PaMtoEditCursor( rPaM ); + Point aBottomRight = aRec.BottomRight(); + aBottomRight.Y() += mpImpl->mpWindow->GetOutputSizePixel().Height() * 9/10; + aBottomRight.X() += 1; + long nHeight = mpImpl->mpTextEngine->GetTextHeight(); + if ( aBottomRight.Y() > nHeight ) + aBottomRight.Y() = nHeight-1; + + TextPaM aPaM = mpImpl->mpTextEngine->GetPaM( aBottomRight ); + return aPaM; +} + +void TextView::ImpShowCursor( sal_Bool bGotoCursor, sal_Bool bForceVisCursor, sal_Bool bSpecial ) +{ + if ( mpImpl->mpTextEngine->IsFormatting() ) + return; + if ( mpImpl->mpTextEngine->GetUpdateMode() == sal_False ) + return; + if ( mpImpl->mpTextEngine->IsInUndo() ) + return; + + mpImpl->mpTextEngine->CheckIdleFormatter(); + if ( !mpImpl->mpTextEngine->IsFormatted() ) + mpImpl->mpTextEngine->FormatAndUpdate( this ); + + + TextPaM aPaM( mpImpl->maSelection.GetEnd() ); + Rectangle aEditCursor = mpImpl->mpTextEngine->PaMtoEditCursor( aPaM, bSpecial ); + + // Remember that we placed the cursor behind the last character of a line + mpImpl->mbCursorAtEndOfLine = false; + if( bSpecial ) + { + TEParaPortion* pParaPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() ); + mpImpl->mbCursorAtEndOfLine = + pParaPortion->GetLineNumber( aPaM.GetIndex(), sal_True ) != pParaPortion->GetLineNumber( aPaM.GetIndex(), sal_False ); + } + + if ( !IsInsertMode() && !mpImpl->maSelection.HasRange() ) + { + TextNode* pNode = mpImpl->mpTextEngine->mpDoc->GetNodes().GetObject( aPaM.GetPara() ); + if ( pNode->GetText().Len() && ( aPaM.GetIndex() < pNode->GetText().Len() ) ) + { + // If we are behind a portion, and the next portion has other direction, we must change position... + aEditCursor.Left() = aEditCursor.Right() = mpImpl->mpTextEngine->GetEditCursor( aPaM, sal_False, sal_True ).Left(); + + TEParaPortion* pParaPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() ); + + sal_uInt16 nTextPortionStart = 0; + sal_uInt16 nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nTextPortionStart, sal_True ); + TETextPortion* pTextPortion = pParaPortion->GetTextPortions()[ nTextPortion ]; + if ( pTextPortion->GetKind() == PORTIONKIND_TAB ) + { + if ( mpImpl->mpTextEngine->IsRightToLeft() ) + { + + } + aEditCursor.Right() += pTextPortion->GetWidth(); + } + else + { + TextPaM aNext = CursorRight( TextPaM( aPaM.GetPara(), aPaM.GetIndex() ), (sal_uInt16)i18n::CharacterIteratorMode::SKIPCELL ); + aEditCursor.Right() = mpImpl->mpTextEngine->GetEditCursor( aNext, sal_True ).Left(); + } + } + } + + Size aOutSz = mpImpl->mpWindow->GetOutputSizePixel(); + if ( aEditCursor.GetHeight() > aOutSz.Height() ) + aEditCursor.Bottom() = aEditCursor.Top() + aOutSz.Height() - 1; + + aEditCursor.Left() -= 1; + + if ( bGotoCursor + // #i81283# protext maStartDocPos against initialization problems + && aOutSz.Width() && aOutSz.Height() + ) + { + long nVisStartY = mpImpl->maStartDocPos.Y(); + long nVisEndY = mpImpl->maStartDocPos.Y() + aOutSz.Height(); + long nVisStartX = mpImpl->maStartDocPos.X(); + long nVisEndX = mpImpl->maStartDocPos.X() + aOutSz.Width(); + long nMoreX = aOutSz.Width() / 4; + + Point aNewStartPos( mpImpl->maStartDocPos ); + + if ( aEditCursor.Bottom() > nVisEndY ) + { + aNewStartPos.Y() += ( aEditCursor.Bottom() - nVisEndY ); + } + else if ( aEditCursor.Top() < nVisStartY ) + { + aNewStartPos.Y() -= ( nVisStartY - aEditCursor.Top() ); + } + + if ( aEditCursor.Right() >= nVisEndX ) + { + aNewStartPos.X() += ( aEditCursor.Right() - nVisEndX ); + + // Darfs ein bischen mehr sein? + aNewStartPos.X() += nMoreX; + } + else if ( aEditCursor.Left() <= nVisStartX ) + { + aNewStartPos.X() -= ( nVisStartX - aEditCursor.Left() ); + + // Darfs ein bischen mehr sein? + aNewStartPos.X() -= nMoreX; + } + + // X kann durch das 'bischen mehr' falsch sein: +// sal_uLong nMaxTextWidth = mpImpl->mpTextEngine->GetMaxTextWidth(); +// if ( !nMaxTextWidth || ( nMaxTextWidth > 0x7FFFFFFF ) ) +// nMaxTextWidth = 0x7FFFFFFF; +// long nMaxX = (long)nMaxTextWidth - aOutSz.Width(); + long nMaxX = mpImpl->mpTextEngine->CalcTextWidth() - aOutSz.Width(); + if ( nMaxX < 0 ) + nMaxX = 0; + + if ( aNewStartPos.X() < 0 ) + aNewStartPos.X() = 0; + else if ( aNewStartPos.X() > nMaxX ) + aNewStartPos.X() = nMaxX; + + // Y sollte nicht weiter unten als noetig liegen: + long nYMax = mpImpl->mpTextEngine->GetTextHeight() - aOutSz.Height(); + if ( nYMax < 0 ) + nYMax = 0; + if ( aNewStartPos.Y() > nYMax ) + aNewStartPos.Y() = nYMax; + + if ( aNewStartPos != mpImpl->maStartDocPos ) + Scroll( -(aNewStartPos.X() - mpImpl->maStartDocPos.X()), -(aNewStartPos.Y() - mpImpl->maStartDocPos.Y()) ); + } + + if ( aEditCursor.Right() < aEditCursor.Left() ) + { + long n = aEditCursor.Left(); + aEditCursor.Left() = aEditCursor.Right(); + aEditCursor.Right() = n; + } + + Point aPoint( GetWindowPos( !mpImpl->mpTextEngine->IsRightToLeft() ? aEditCursor.TopLeft() : aEditCursor.TopRight() ) ); + mpImpl->mpCursor->SetPos( aPoint ); + mpImpl->mpCursor->SetSize( aEditCursor.GetSize() ); + if ( bForceVisCursor && mpImpl->mbCursorEnabled ) + mpImpl->mpCursor->Show(); +} + +sal_Bool TextView::SetCursorAtPoint( const Point& rPosPixel ) +{ + mpImpl->mpTextEngine->CheckIdleFormatter(); + + Point aDocPos = GetDocPos( rPosPixel ); + + TextPaM aPaM = mpImpl->mpTextEngine->GetPaM( aDocPos ); + + // aTmpNewSel: Diff zwischen alt und neu, nicht die neue Selektion + TextSelection aTmpNewSel( mpImpl->maSelection.GetEnd(), aPaM ); + TextSelection aNewSel( mpImpl->maSelection ); + aNewSel.GetEnd() = aPaM; + + if ( !mpImpl->mpSelEngine->HasAnchor() ) + { + if ( mpImpl->maSelection.GetStart() != aPaM ) + mpImpl->mpTextEngine->CursorMoved( mpImpl->maSelection.GetStart().GetPara() ); + aNewSel.GetStart() = aPaM; + ImpSetSelection( aNewSel ); + } + else + { + ImpSetSelection( aNewSel ); + ShowSelection( aTmpNewSel ); + } + + sal_Bool bForceCursor = mpImpl->mpDDInfo ? sal_False : sal_True; // && !mbInSelection + ImpShowCursor( mpImpl->mbAutoScroll, bForceCursor, sal_False ); + return sal_True; +} + +sal_Bool TextView::IsSelectionAtPoint( const Point& rPosPixel ) +{ +// if ( !Rectangle( Point(), mpImpl->mpWindow->GetOutputSizePixel() ).IsInside( rPosPixel ) && !mbInSelection ) +// return sal_False; + + Point aDocPos = GetDocPos( rPosPixel ); + TextPaM aPaM = mpImpl->mpTextEngine->GetPaM( aDocPos, sal_False ); + // Bei Hyperlinks D&D auch ohne Selektion starten. + // BeginDrag wird aber nur gerufen, wenn IsSelectionAtPoint() + // Problem: IsSelectionAtPoint wird bei Command() nicht gerufen, + // wenn vorher im MBDown schon sal_False returnt wurde. + return ( IsInSelection( aPaM ) || + ( /* mpImpl->mpSelEngine->IsInCommand() && */ mpImpl->mpTextEngine->FindAttrib( aPaM, TEXTATTR_HYPERLINK ) ) ); +} + +sal_Bool TextView::IsInSelection( const TextPaM& rPaM ) +{ + TextSelection aSel = mpImpl->maSelection; + aSel.Justify(); + + sal_uLong nStartNode = aSel.GetStart().GetPara(); + sal_uLong nEndNode = aSel.GetEnd().GetPara(); + sal_uLong nCurNode = rPaM.GetPara(); + + if ( ( nCurNode > nStartNode ) && ( nCurNode < nEndNode ) ) + return sal_True; + + if ( nStartNode == nEndNode ) + { + if ( nCurNode == nStartNode ) + if ( ( rPaM.GetIndex() >= aSel.GetStart().GetIndex() ) && ( rPaM.GetIndex() < aSel.GetEnd().GetIndex() ) ) + return sal_True; + } + else if ( ( nCurNode == nStartNode ) && ( rPaM.GetIndex() >= aSel.GetStart().GetIndex() ) ) + return sal_True; + else if ( ( nCurNode == nEndNode ) && ( rPaM.GetIndex() < aSel.GetEnd().GetIndex() ) ) + return sal_True; + + return sal_False; +} + +void TextView::ImpHideDDCursor() +{ + if ( mpImpl->mpDDInfo && mpImpl->mpDDInfo->mbVisCursor ) + { + mpImpl->mpDDInfo->maCursor.Hide(); + mpImpl->mpDDInfo->mbVisCursor = sal_False; + } +} + +void TextView::ImpShowDDCursor() +{ + if ( !mpImpl->mpDDInfo->mbVisCursor ) + { + Rectangle aCursor = mpImpl->mpTextEngine->PaMtoEditCursor( mpImpl->mpDDInfo->maDropPos, sal_True ); + aCursor.Right()++; + aCursor.SetPos( GetWindowPos( aCursor.TopLeft() ) ); + + mpImpl->mpDDInfo->maCursor.SetWindow( mpImpl->mpWindow ); + mpImpl->mpDDInfo->maCursor.SetPos( aCursor.TopLeft() ); + mpImpl->mpDDInfo->maCursor.SetSize( aCursor.GetSize() ); + mpImpl->mpDDInfo->maCursor.Show(); + mpImpl->mpDDInfo->mbVisCursor = sal_True; + } +} + +void TextView::SetPaintSelection( sal_Bool bPaint ) +{ + if ( bPaint != mpImpl->mbPaintSelection ) + { + mpImpl->mbPaintSelection = bPaint; + ShowSelection( mpImpl->maSelection ); + } +} + +sal_Bool TextView::Read( SvStream& rInput ) +{ + sal_Bool bDone = mpImpl->mpTextEngine->Read( rInput, &mpImpl->maSelection ); + ShowCursor(); + return bDone; +} + +bool TextView::ImplTruncateNewText( rtl::OUString& rNewText ) const +{ + bool bTruncated = false; + + if( rNewText.getLength() > 65534 ) // limit to String API + { + rNewText = rNewText.copy( 0, 65534 ); + bTruncated = true; + } + + sal_uLong nMaxLen = mpImpl->mpTextEngine->GetMaxTextLen(); + // 0 means unlimited, there is just the String API limit handled above + if( nMaxLen != 0 ) + { + sal_uLong nCurLen = mpImpl->mpTextEngine->GetTextLen(); + + sal_uInt32 nNewLen = rNewText.getLength(); + if ( nCurLen + nNewLen > nMaxLen ) + { + // see how much text will be replaced + sal_uLong nSelLen = mpImpl->mpTextEngine->GetTextLen( mpImpl->maSelection ); + if ( nCurLen + nNewLen - nSelLen > nMaxLen ) + { + sal_uInt32 nTruncatedLen = static_cast(nMaxLen - (nCurLen - nSelLen)); + rNewText = rNewText.copy( 0, nTruncatedLen ); + bTruncated = true; + } + } + } + return bTruncated; +} + +sal_Bool TextView::ImplCheckTextLen( const String& rNewText ) +{ + sal_Bool bOK = sal_True; + if ( mpImpl->mpTextEngine->GetMaxTextLen() ) + { + sal_uLong n = mpImpl->mpTextEngine->GetTextLen(); + n += rNewText.Len(); + if ( n > mpImpl->mpTextEngine->GetMaxTextLen() ) + { + // nur dann noch ermitteln, wie viel Text geloescht wird + n -= mpImpl->mpTextEngine->GetTextLen( mpImpl->maSelection ); + if ( n > mpImpl->mpTextEngine->GetMaxTextLen() ) + bOK = sal_False; + } + } + return bOK; +} + +void TextView::dragGestureRecognized( const ::com::sun::star::datatransfer::dnd::DragGestureEvent& rDGE ) throw (::com::sun::star::uno::RuntimeException) +{ + if ( mpImpl->mbClickedInSelection ) + { + SolarMutexGuard aVclGuard; + + DBG_ASSERT( mpImpl->maSelection.HasRange(), "TextView::dragGestureRecognized: mpImpl->mbClickedInSelection, but no selection?" ); + + delete mpImpl->mpDDInfo; + mpImpl->mpDDInfo = new TextDDInfo; + mpImpl->mpDDInfo->mbStarterOfDD = sal_True; + + TETextDataObject* pDataObj = new TETextDataObject( GetSelected() ); + + if ( mpImpl->mpTextEngine->HasAttrib( TEXTATTR_HYPERLINK ) ) // Dann auch als HTML + mpImpl->mpTextEngine->Write( pDataObj->GetHTMLStream(), &mpImpl->maSelection, sal_True ); + + + /* + // D&D eines Hyperlinks. + // Besser waere es im MBDown sich den MBDownPaM zu merken, + // ist dann aber inkompatibel => spaeter mal umstellen. + TextPaM aPaM( mpImpl->mpTextEngine->GetPaM( GetDocPos( GetWindow()->GetPointerPosPixel() ) ) ); + const TextCharAttrib* pAttr = mpImpl->mpTextEngine->FindCharAttrib( aPaM, TEXTATTR_HYPERLINK ); + if ( pAttr ) + { + aSel = aPaM; + aSel.GetStart().GetIndex() = pAttr->GetStart(); + aSel.GetEnd().GetIndex() = pAttr->GetEnd(); + + const TextAttribHyperLink& rLink = (const TextAttribHyperLink&)pAttr->GetAttr(); + String aText( rLink.GetDescription() ); + if ( !aText.Len() ) + aText = mpImpl->mpTextEngine->GetText( aSel ); + INetBookmark aBookmark( rLink.GetURL(), aText ); + aBookmark.CopyDragServer(); + } + */ + + mpImpl->mpCursor->Hide(); + + sal_Int8 nActions = datatransfer::dnd::DNDConstants::ACTION_COPY; + if ( !IsReadOnly() ) + nActions |= datatransfer::dnd::DNDConstants::ACTION_MOVE; + rDGE.DragSource->startDrag( rDGE, nActions, 0 /*cursor*/, 0 /*image*/, pDataObj, mpImpl->mxDnDListener ); + } +} + +void TextView::dragDropEnd( const ::com::sun::star::datatransfer::dnd::DragSourceDropEvent& ) throw (::com::sun::star::uno::RuntimeException) +{ + ImpHideDDCursor(); + delete mpImpl->mpDDInfo; + mpImpl->mpDDInfo = NULL; +} + +void TextView::drop( const ::com::sun::star::datatransfer::dnd::DropTargetDropEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException) +{ + SolarMutexGuard aVclGuard; + + sal_Bool bChanges = sal_False; + if ( !mpImpl->mbReadOnly && mpImpl->mpDDInfo ) + { + ImpHideDDCursor(); + + // Daten fuer das loeschen nach einem DROP_MOVE: + TextSelection aPrevSel( mpImpl->maSelection ); + aPrevSel.Justify(); + sal_uLong nPrevParaCount = mpImpl->mpTextEngine->GetParagraphCount(); + sal_uInt16 nPrevStartParaLen = mpImpl->mpTextEngine->GetTextLen( aPrevSel.GetStart().GetPara() ); + + sal_Bool bStarterOfDD = sal_False; + for ( sal_uInt16 nView = mpImpl->mpTextEngine->GetViewCount(); nView && !bStarterOfDD; ) + bStarterOfDD = mpImpl->mpTextEngine->GetView( --nView )->mpImpl->mpDDInfo ? mpImpl->mpTextEngine->GetView( nView )->mpImpl->mpDDInfo->mbStarterOfDD : sal_False; + + HideSelection(); + ImpSetSelection( mpImpl->mpDDInfo->maDropPos ); + + mpImpl->mpTextEngine->UndoActionStart(); + + String aText; + uno::Reference< datatransfer::XTransferable > xDataObj = rDTDE.Transferable; + if ( xDataObj.is() ) + { + datatransfer::DataFlavor aFlavor; + SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor ); + if ( xDataObj->isDataFlavorSupported( aFlavor ) ) + { + uno::Any aData = xDataObj->getTransferData( aFlavor ); + ::rtl::OUString aOUString; + aData >>= aOUString; + aText = convertLineEnd(aOUString, LINEEND_LF); + } + } + + if ( aText.Len() && ( aText.GetChar( aText.Len()-1 ) == LINE_SEP ) ) + aText.Erase( aText.Len()-1 ); + + TextPaM aTempStart = mpImpl->maSelection.GetStart(); + if ( ImplCheckTextLen( aText ) ) + ImpSetSelection( mpImpl->mpTextEngine->ImpInsertText( mpImpl->mpDDInfo->maDropPos, aText ) ); + if(mpImpl->mbSupportProtectAttribute) + { + mpImpl->mpTextEngine->SetAttrib( TextAttribProtect(), + aTempStart.GetPara(), + aTempStart.GetIndex(), + mpImpl->maSelection.GetEnd().GetIndex(), sal_False ); + } + + if ( aPrevSel.HasRange() && + !mpImpl->mbSupportProtectAttribute && // don't remove currently selected element + (( rDTDE.DropAction & datatransfer::dnd::DNDConstants::ACTION_MOVE ) || !bStarterOfDD) ) + { + // ggf. Selection anpasssen: + if ( ( mpImpl->mpDDInfo->maDropPos.GetPara() < aPrevSel.GetStart().GetPara() ) || + ( ( mpImpl->mpDDInfo->maDropPos.GetPara() == aPrevSel.GetStart().GetPara() ) + && ( mpImpl->mpDDInfo->maDropPos.GetIndex() < aPrevSel.GetStart().GetIndex() ) ) ) + { + sal_uLong nNewParasBeforeSelection = + mpImpl->mpTextEngine->GetParagraphCount() - nPrevParaCount; + + aPrevSel.GetStart().GetPara() += nNewParasBeforeSelection; + aPrevSel.GetEnd().GetPara() += nNewParasBeforeSelection; + + if ( mpImpl->mpDDInfo->maDropPos.GetPara() == aPrevSel.GetStart().GetPara() ) + { + sal_uInt16 nNewChars = + mpImpl->mpTextEngine->GetTextLen( aPrevSel.GetStart().GetPara() ) - nPrevStartParaLen; + + aPrevSel.GetStart().GetIndex() = + aPrevSel.GetStart().GetIndex() + nNewChars; + if ( aPrevSel.GetStart().GetPara() == aPrevSel.GetEnd().GetPara() ) + aPrevSel.GetEnd().GetIndex() = + aPrevSel.GetEnd().GetIndex() + nNewChars; + } + } + else + { + // aktuelle Selektion anpassen + TextPaM aPaM = mpImpl->maSelection.GetStart(); + aPaM.GetPara() -= ( aPrevSel.GetEnd().GetPara() - aPrevSel.GetStart().GetPara() ); + if ( aPrevSel.GetEnd().GetPara() == mpImpl->mpDDInfo->maDropPos.GetPara() ) + { + aPaM.GetIndex() = + aPaM.GetIndex() - aPrevSel.GetEnd().GetIndex(); + if ( aPrevSel.GetStart().GetPara() == mpImpl->mpDDInfo->maDropPos.GetPara() ) + aPaM.GetIndex() = + aPaM.GetIndex() + aPrevSel.GetStart().GetIndex(); + } + ImpSetSelection( aPaM ); + + } + mpImpl->mpTextEngine->ImpDeleteText( aPrevSel ); + } + + mpImpl->mpTextEngine->UndoActionEnd(); + + delete mpImpl->mpDDInfo; + mpImpl->mpDDInfo = 0; + + mpImpl->mpTextEngine->FormatAndUpdate( this ); + + mpImpl->mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) ); + } + rDTDE.Context->dropComplete( bChanges ); +} + +void TextView::dragEnter( const ::com::sun::star::datatransfer::dnd::DropTargetDragEnterEvent& ) throw (::com::sun::star::uno::RuntimeException) +{ +} + +void TextView::dragExit( const ::com::sun::star::datatransfer::dnd::DropTargetEvent& ) throw (::com::sun::star::uno::RuntimeException) +{ + SolarMutexGuard aVclGuard; + ImpHideDDCursor(); +} + +void TextView::dragOver( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException) +{ + SolarMutexGuard aVclGuard; + + if ( !mpImpl->mpDDInfo ) + mpImpl->mpDDInfo = new TextDDInfo; + + TextPaM aPrevDropPos = mpImpl->mpDDInfo->maDropPos; + Point aMousePos( rDTDE.LocationX, rDTDE.LocationY ); + Point aDocPos = GetDocPos( aMousePos ); + mpImpl->mpDDInfo->maDropPos = mpImpl->mpTextEngine->GetPaM( aDocPos ); + + sal_Bool bProtected = sal_False; + if(mpImpl->mbSupportProtectAttribute) + { + const TextCharAttrib* pStartAttr = mpImpl->mpTextEngine->FindCharAttrib( + mpImpl->mpDDInfo->maDropPos, + TEXTATTR_PROTECTED ); + bProtected = pStartAttr != 0 && + pStartAttr->GetStart() != mpImpl->mpDDInfo->maDropPos.GetIndex() && + pStartAttr->GetEnd() != mpImpl->mpDDInfo->maDropPos.GetIndex(); + } + // Don't drop in selection or in read only engine + if ( IsReadOnly() || IsInSelection( mpImpl->mpDDInfo->maDropPos ) || bProtected) + { + ImpHideDDCursor(); + rDTDE.Context->rejectDrag(); + } + else + { + // Alten Cursor wegzeichnen... + if ( !mpImpl->mpDDInfo->mbVisCursor || ( aPrevDropPos != mpImpl->mpDDInfo->maDropPos ) ) + { + ImpHideDDCursor(); + ImpShowDDCursor(); + } + rDTDE.Context->acceptDrag( rDTDE.DropAction ); + } +} + +Point TextView::ImpGetOutputStartPos( const Point& rStartDocPos ) const +{ + Point aStartPos( -rStartDocPos.X(), -rStartDocPos.Y() ); + if ( mpImpl->mpTextEngine->IsRightToLeft() ) + { + Size aSz = mpImpl->mpWindow->GetOutputSizePixel(); + aStartPos.X() = rStartDocPos.X() + aSz.Width() - 1; // -1: Start is 0 + } + return aStartPos; +} + +Point TextView::GetDocPos( const Point& rWindowPos ) const +{ + // Fensterposition => Dokumentposition + + Point aPoint; + + aPoint.Y() = rWindowPos.Y() + mpImpl->maStartDocPos.Y(); + + if ( !mpImpl->mpTextEngine->IsRightToLeft() ) + { + aPoint.X() = rWindowPos.X() + mpImpl->maStartDocPos.X(); + } + else + { + Size aSz = mpImpl->mpWindow->GetOutputSizePixel(); + aPoint.X() = ( aSz.Width() - 1 ) - rWindowPos.X() + mpImpl->maStartDocPos.X(); + } + + return aPoint; +} + +Point TextView::GetWindowPos( const Point& rDocPos ) const +{ + // Dokumentposition => Fensterposition + + Point aPoint; + + aPoint.Y() = rDocPos.Y() - mpImpl->maStartDocPos.Y(); + + if ( !mpImpl->mpTextEngine->IsRightToLeft() ) + { + aPoint.X() = rDocPos.X() - mpImpl->maStartDocPos.X(); + } + else + { + Size aSz = mpImpl->mpWindow->GetOutputSizePixel(); + aPoint.X() = ( aSz.Width() - 1 ) - ( rDocPos.X() - mpImpl->maStartDocPos.X() ); + } + + return aPoint; +} + +sal_Int32 TextView::GetLineNumberOfCursorInSelection() const +{ + // PROGRESS + sal_Int32 nLineNo = -1; + if( mpImpl->mbCursorEnabled ) + { + TextPaM aPaM = GetSelection().GetEnd(); + TEParaPortion* pPPortion = mpImpl->mpTextEngine->mpTEParaPortions->GetObject( aPaM.GetPara() ); + nLineNo = pPPortion->GetLineNumber( aPaM.GetIndex(), sal_False ); + if( mpImpl->mbCursorAtEndOfLine ) + --nLineNo; + } + return nLineNo; +} + + +// ------------------------------------------------------------------------- +// (+) class TextSelFunctionSet +// ------------------------------------------------------------------------- +TextSelFunctionSet::TextSelFunctionSet( TextView* pView ) +{ + mpView = pView; +} + +void TextSelFunctionSet::BeginDrag() +{ +} + +void TextSelFunctionSet::CreateAnchor() +{ +// TextSelection aSel( mpView->GetSelection() ); +// aSel.GetStart() = aSel.GetEnd(); +// mpView->SetSelection( aSel ); + + // Es darf kein ShowCursor folgen: + mpView->HideSelection(); + mpView->ImpSetSelection( mpView->mpImpl->maSelection.GetEnd() ); +} + +sal_Bool TextSelFunctionSet::SetCursorAtPoint( const Point& rPointPixel, sal_Bool ) +{ + return mpView->SetCursorAtPoint( rPointPixel ); +} + +sal_Bool TextSelFunctionSet::IsSelectionAtPoint( const Point& rPointPixel ) +{ + return mpView->IsSelectionAtPoint( rPointPixel ); +} + +void TextSelFunctionSet::DeselectAll() +{ + CreateAnchor(); +} + +void TextSelFunctionSet::DeselectAtPoint( const Point& ) +{ + // Nur bei Mehrfachselektion +} + +void TextSelFunctionSet::DestroyAnchor() +{ + // Nur bei Mehrfachselektion +} +TextEngine* TextView::GetTextEngine() const +{ return mpImpl->mpTextEngine; } +Window* TextView::GetWindow() const +{ return mpImpl->mpWindow; } +void TextView::EnableCursor( sal_Bool bEnable ) +{ mpImpl->mbCursorEnabled = bEnable; } +sal_Bool TextView::IsCursorEnabled() const +{ return mpImpl->mbCursorEnabled; } +void TextView::SetStartDocPos( const Point& rPos ) +{ mpImpl->maStartDocPos = rPos; } +const Point& TextView::GetStartDocPos() const +{ return mpImpl->maStartDocPos; } +void TextView::SetAutoIndentMode( sal_Bool bAutoIndent ) +{ mpImpl->mbAutoIndent = bAutoIndent; } +sal_Bool TextView::IsReadOnly() const +{ return mpImpl->mbReadOnly; } +void TextView::SetAutoScroll( sal_Bool bAutoScroll ) +{ mpImpl->mbAutoScroll = bAutoScroll; } +sal_Bool TextView::IsAutoScroll() const +{ return mpImpl->mbAutoScroll; } +sal_Bool TextView::HasSelection() const +{ return mpImpl->maSelection.HasRange(); } +sal_Bool TextView::IsInsertMode() const +{ return mpImpl->mbInsertMode; } +void TextView::SupportProtectAttribute(sal_Bool bSupport) +{ mpImpl->mbSupportProtectAttribute = bSupport;} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/edit/txtattr.cxx b/vcl/source/edit/txtattr.cxx new file mode 100644 index 0000000..d0e3a84 --- /dev/null +++ b/vcl/source/edit/txtattr.cxx @@ -0,0 +1,164 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include +#include + + + + +TextAttrib::~TextAttrib() +{ +} + +int TextAttrib::operator==( const TextAttrib& rAttr ) const +{ + return mnWhich == rAttr.mnWhich; +} + + +TextAttribFontColor::TextAttribFontColor( const Color& rColor ) + : TextAttrib( TEXTATTR_FONTCOLOR ), maColor( rColor ) +{ +} + +TextAttribFontColor::TextAttribFontColor( const TextAttribFontColor& rAttr ) + : TextAttrib( rAttr ), maColor( rAttr.maColor ) +{ +} + +TextAttribFontColor::~TextAttribFontColor() +{ +} + +void TextAttribFontColor::SetFont( Font& rFont ) const +{ + rFont.SetColor( maColor ); +} + +TextAttrib* TextAttribFontColor::Clone() const +{ + return new TextAttribFontColor( *this ); +} + +int TextAttribFontColor::operator==( const TextAttrib& rAttr ) const +{ + return ( ( TextAttrib::operator==(rAttr ) ) && + ( maColor == ((const TextAttribFontColor&)rAttr).maColor ) ); +} + +TextAttribFontWeight::TextAttribFontWeight( FontWeight eWeight ) + : TextAttrib( TEXTATTR_FONTWEIGHT ), meWeight( eWeight ) +{ +} + +TextAttribFontWeight::TextAttribFontWeight( const TextAttribFontWeight& rAttr ) + : TextAttrib( rAttr ), meWeight( rAttr.meWeight ) +{ +} + +TextAttribFontWeight::~TextAttribFontWeight() +{ +} + +void TextAttribFontWeight::SetFont( Font& rFont ) const +{ + rFont.SetWeight( meWeight ); +} + +TextAttrib* TextAttribFontWeight::Clone() const +{ + return new TextAttribFontWeight( *this ); +} + +int TextAttribFontWeight::operator==( const TextAttrib& rAttr ) const +{ + return ( ( TextAttrib::operator==(rAttr ) ) && + ( meWeight == ((const TextAttribFontWeight&)rAttr).meWeight ) ); +} + + +TextAttribHyperLink::TextAttribHyperLink( const TextAttribHyperLink& rAttr ) + : TextAttrib( rAttr ), maURL( rAttr.maURL ), maDescription( rAttr.maDescription ) +{ + maColor = rAttr.maColor; +} + +TextAttribHyperLink::~TextAttribHyperLink() +{ +} + +void TextAttribHyperLink::SetFont( Font& rFont ) const +{ + rFont.SetColor( maColor ); + rFont.SetUnderline( UNDERLINE_SINGLE ); +} + +TextAttrib* TextAttribHyperLink::Clone() const +{ + return new TextAttribHyperLink( *this ); +} + +int TextAttribHyperLink::operator==( const TextAttrib& rAttr ) const +{ + return ( ( TextAttrib::operator==(rAttr ) ) && + ( maURL == ((const TextAttribHyperLink&)rAttr).maURL ) && + ( maDescription == ((const TextAttribHyperLink&)rAttr).maDescription ) && + ( maColor == ((const TextAttribHyperLink&)rAttr).maColor ) ); +} + +TextAttribProtect::TextAttribProtect() : + TextAttrib( TEXTATTR_PROTECTED ) +{ +} + +TextAttribProtect::TextAttribProtect( const TextAttribProtect&) : + TextAttrib( TEXTATTR_PROTECTED ) +{ +} + +TextAttribProtect::~TextAttribProtect() +{ +} + +void TextAttribProtect::SetFont( Font& ) const +{ +} + +TextAttrib* TextAttribProtect::Clone() const +{ + return new TextAttribProtect(); +} + +int TextAttribProtect::operator==( const TextAttrib& rAttr ) const +{ + return ( TextAttrib::operator==(rAttr ) ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/edit/vclmedit.cxx b/vcl/source/edit/vclmedit.cxx new file mode 100644 index 0000000..2262c74 --- /dev/null +++ b/vcl/source/edit/vclmedit.cxx @@ -0,0 +1,1572 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + + +class TextWindow : public Window +{ +private: + ExtTextEngine* mpTextEngine; + ExtTextView* mpTextView; + + sal_Bool mbInMBDown; + sal_Bool mbFocusSelectionHide; + sal_Bool mbIgnoreTab; + sal_Bool mbActivePopup; + sal_Bool mbSelectOnTab; + sal_Bool mbTextSelectable; + +public: + TextWindow( Window* pParent ); + ~TextWindow(); + + ExtTextEngine* GetTextEngine() const { return mpTextEngine; } + ExtTextView* GetTextView() const { return mpTextView; } + + virtual void MouseMove( const MouseEvent& rMEvt ); + virtual void MouseButtonDown( const MouseEvent& rMEvt ); + virtual void MouseButtonUp( const MouseEvent& rMEvt ); + virtual void KeyInput( const KeyEvent& rKEvent ); + + virtual void Command( const CommandEvent& rCEvt ); + + virtual void Paint( const Rectangle& rRect ); + virtual void Resize(); + + virtual void GetFocus(); + virtual void LoseFocus(); + + sal_Bool IsAutoFocusHide() const { return mbFocusSelectionHide; } + void SetAutoFocusHide( sal_Bool bAutoHide ) { mbFocusSelectionHide = bAutoHide; } + + sal_Bool IsIgnoreTab() const { return mbIgnoreTab; } + void SetIgnoreTab( sal_Bool bIgnore ) { mbIgnoreTab = bIgnore; } + + void DisableSelectionOnFocus() { mbSelectOnTab = sal_False; } + + void SetTextSelectable( sal_Bool bTextSelectable ) { mbTextSelectable = bTextSelectable; } +}; + + +class ImpSvMEdit : public SfxListener +{ +private: + VCLMultiLineEdit* pSvVCLMultiLineEdit; + + TextWindow* mpTextWindow; + ScrollBar* mpHScrollBar; + ScrollBar* mpVScrollBar; + ScrollBarBox* mpScrollBox; + + Point maTextWindowOffset; + xub_StrLen mnTextWidth; + mutable Selection maSelection; + +protected: + virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ); + void ImpUpdateSrollBarVis( WinBits nWinStyle ); + void ImpInitScrollBars(); + void ImpSetScrollBarRanges(); + void ImpSetHScrollBarThumbPos(); + DECL_LINK( ScrollHdl, ScrollBar* ); + +public: + ImpSvMEdit( VCLMultiLineEdit* pSvVCLMultiLineEdit, WinBits nWinStyle ); + ~ImpSvMEdit(); + + void SetModified( sal_Bool bMod ); + sal_Bool IsModified() const; + + void SetReadOnly( sal_Bool bRdOnly ); + sal_Bool IsReadOnly() const; + + void SetMaxTextLen( xub_StrLen nLen ); + xub_StrLen GetMaxTextLen() const; + + sal_Bool IsInsertMode() const; + + void InsertText( const String& rStr ); + String GetSelected() const; + String GetSelected( LineEnd aSeparator ) const; + + void SetSelection( const Selection& rSelection ); + const Selection& GetSelection() const; + + void Cut(); + void Copy(); + void Paste(); + + void SetText( const String& rStr ); + String GetText() const; + String GetText( LineEnd aSeparator ) const; + String GetTextLines( LineEnd aSeparator ) const; + + void Resize(); + void GetFocus(); + + sal_Bool HandleCommand( const CommandEvent& rCEvt ); + + void Enable( sal_Bool bEnable ); + + Size CalcMinimumSize() const; + Size CalcSize( sal_uInt16 nColumns, sal_uInt16 nLines ) const; + void GetMaxVisColumnsAndLines( sal_uInt16& rnCols, sal_uInt16& rnLines ) const; + + void SetAlign( WinBits nWinStyle ); + + void InitFromStyle( WinBits nWinStyle ); + + TextWindow* GetTextWindow() { return mpTextWindow; } + ScrollBar* GetHScrollBar() { return mpHScrollBar; } + ScrollBar* GetVScrollBar() { return mpVScrollBar; } +}; + +ImpSvMEdit::ImpSvMEdit( VCLMultiLineEdit* pEdt, WinBits nWinStyle ) + :mpHScrollBar(NULL) + ,mpVScrollBar(NULL) + ,mpScrollBox(NULL) +{ + pSvVCLMultiLineEdit = pEdt; + mnTextWidth = 0; + mpTextWindow = new TextWindow( pEdt ); + mpTextWindow->Show(); + InitFromStyle( nWinStyle ); + StartListening( *mpTextWindow->GetTextEngine() ); +} + +void ImpSvMEdit::ImpUpdateSrollBarVis( WinBits nWinStyle ) +{ + const sal_Bool bHaveVScroll = (NULL != mpVScrollBar); + const sal_Bool bHaveHScroll = (NULL != mpHScrollBar); + const sal_Bool bHaveScrollBox = (NULL != mpScrollBox); + + sal_Bool bNeedVScroll = ( nWinStyle & WB_VSCROLL ) == WB_VSCROLL; + const sal_Bool bNeedHScroll = ( nWinStyle & WB_HSCROLL ) == WB_HSCROLL; + + const sal_Bool bAutoVScroll = ( nWinStyle & WB_AUTOVSCROLL ) == WB_AUTOVSCROLL; + if ( !bNeedVScroll && bAutoVScroll ) + { + TextEngine& rEngine( *mpTextWindow->GetTextEngine() ); + sal_uLong nOverallTextHeight(0); + for ( sal_uLong i=0; i (sal_uLong)mpTextWindow->GetOutputSizePixel().Height() ) + bNeedVScroll = true; + } + + const sal_Bool bNeedScrollBox = bNeedVScroll && bNeedHScroll; + + sal_Bool bScrollbarsChanged = false; + if ( bHaveVScroll != bNeedVScroll ) + { + delete mpVScrollBar; + mpVScrollBar = bNeedVScroll ? new ScrollBar( pSvVCLMultiLineEdit, WB_VSCROLL|WB_DRAG ) : NULL; + + if ( bNeedVScroll ) + { + mpVScrollBar->Show(); + mpVScrollBar->SetScrollHdl( LINK( this, ImpSvMEdit, ScrollHdl ) ); + } + + bScrollbarsChanged = sal_True; + } + + if ( bHaveHScroll != bNeedHScroll ) + { + delete mpHScrollBar; + mpHScrollBar = bNeedHScroll ? new ScrollBar( pSvVCLMultiLineEdit, WB_HSCROLL|WB_DRAG ) : NULL; + + if ( bNeedHScroll ) + { + mpHScrollBar->Show(); + mpHScrollBar->SetScrollHdl( LINK( this, ImpSvMEdit, ScrollHdl ) ); + } + + bScrollbarsChanged = sal_True; + } + + if ( bHaveScrollBox != bNeedScrollBox ) + { + delete mpScrollBox; + mpScrollBox = bNeedScrollBox ? new ScrollBarBox( pSvVCLMultiLineEdit, WB_SIZEABLE ) : NULL; + + if ( bNeedScrollBox ) + mpScrollBox->Show(); + } + + if ( bScrollbarsChanged ) + { + ImpInitScrollBars(); + Resize(); + } +} + +void ImpSvMEdit::InitFromStyle( WinBits nWinStyle ) +{ + ImpUpdateSrollBarVis( nWinStyle ); + SetAlign( nWinStyle ); + + if ( nWinStyle & WB_NOHIDESELECTION ) + mpTextWindow->SetAutoFocusHide( sal_False ); + else + mpTextWindow->SetAutoFocusHide( sal_True ); + + if ( nWinStyle & WB_READONLY ) + mpTextWindow->GetTextView()->SetReadOnly( sal_True ); + else + mpTextWindow->GetTextView()->SetReadOnly( sal_False ); + + if ( nWinStyle & WB_IGNORETAB ) + { + mpTextWindow->SetIgnoreTab( sal_True ); + } + else + { + mpTextWindow->SetIgnoreTab( sal_False ); + // #103667# VCLMultiLineEdit has the flag, but focusable window also needs this flag + WinBits nStyle = mpTextWindow->GetStyle(); + nStyle |= WINDOW_DLGCTRL_MOD1TAB; + mpTextWindow->SetStyle( nStyle ); + } +} + +ImpSvMEdit::~ImpSvMEdit() +{ + EndListening( *mpTextWindow->GetTextEngine() ); + delete mpTextWindow; + delete mpHScrollBar; + delete mpVScrollBar; + delete mpScrollBox; +} + +void ImpSvMEdit::ImpSetScrollBarRanges() +{ + if ( mpVScrollBar ) + { + sal_uLong nTextHeight = mpTextWindow->GetTextEngine()->GetTextHeight(); + mpVScrollBar->SetRange( Range( 0, (long)nTextHeight-1 ) ); + } + if ( mpHScrollBar ) + { +// sal_uLong nTextWidth = mpTextWindow->GetTextEngine()->CalcTextWidth(); + // Es gibt kein Notify bei Breiten-Aenderung... +// sal_uLong nW = Max( (sal_uLong)mpTextWindow->GetOutputSizePixel().Width()*5, (sal_uLong)nTextWidth ); +// mpHScrollBar->SetRange( Range( 0, (long)nW ) ); + mpHScrollBar->SetRange( Range( 0, (long)mnTextWidth-1 ) ); + } +} + +void ImpSvMEdit::ImpInitScrollBars() +{ + static const sal_Unicode sampleChar = { 'x' }; + if ( mpHScrollBar || mpVScrollBar ) + { + ImpSetScrollBarRanges(); + Size aCharBox; + aCharBox.Width() = mpTextWindow->GetTextWidth( rtl::OUString(sampleChar) ); + aCharBox.Height() = mpTextWindow->GetTextHeight(); + Size aOutSz = mpTextWindow->GetOutputSizePixel(); + if ( mpHScrollBar ) + { + mpHScrollBar->SetVisibleSize( aOutSz.Width() ); + mpHScrollBar->SetPageSize( aOutSz.Width() * 8 / 10 ); + mpHScrollBar->SetLineSize( aCharBox.Width()*10 ); + ImpSetHScrollBarThumbPos(); + } + if ( mpVScrollBar ) + { + mpVScrollBar->SetVisibleSize( aOutSz.Height() ); + mpVScrollBar->SetPageSize( aOutSz.Height() * 8 / 10 ); + mpVScrollBar->SetLineSize( aCharBox.Height() ); + mpVScrollBar->SetThumbPos( mpTextWindow->GetTextView()->GetStartDocPos().Y() ); + } + } +} + +void ImpSvMEdit::ImpSetHScrollBarThumbPos() +{ + long nX = mpTextWindow->GetTextView()->GetStartDocPos().X(); + if ( !mpTextWindow->GetTextEngine()->IsRightToLeft() ) + mpHScrollBar->SetThumbPos( nX ); + else + mpHScrollBar->SetThumbPos( mnTextWidth - mpHScrollBar->GetVisibleSize() - nX ); + +} + +IMPL_LINK( ImpSvMEdit, ScrollHdl, ScrollBar*, pCurScrollBar ) +{ + long nDiffX = 0, nDiffY = 0; + + if ( pCurScrollBar == mpVScrollBar ) + nDiffY = mpTextWindow->GetTextView()->GetStartDocPos().Y() - pCurScrollBar->GetThumbPos(); + else if ( pCurScrollBar == mpHScrollBar ) + nDiffX = mpTextWindow->GetTextView()->GetStartDocPos().X() - pCurScrollBar->GetThumbPos(); + + mpTextWindow->GetTextView()->Scroll( nDiffX, nDiffY ); + // mpTextWindow->GetTextView()->ShowCursor( sal_False, sal_True ); + + return 0; +} + + +// void ImpSvMEdit::ImpModified() +// { +// // Wann wird das gerufen ????????????????????? +// pSvVCLMultiLineEdit->Modify(); +// } + +void ImpSvMEdit::SetAlign( WinBits nWinStyle ) +{ + sal_Bool bRTL = Application::GetSettings().GetLayoutRTL(); + mpTextWindow->GetTextEngine()->SetRightToLeft( bRTL ); + + if ( nWinStyle & WB_CENTER ) + mpTextWindow->GetTextEngine()->SetTextAlign( TXTALIGN_CENTER ); + else if ( nWinStyle & WB_RIGHT ) + mpTextWindow->GetTextEngine()->SetTextAlign( !bRTL ? TXTALIGN_RIGHT : TXTALIGN_LEFT ); + else if ( nWinStyle & WB_LEFT ) + mpTextWindow->GetTextEngine()->SetTextAlign( !bRTL ? TXTALIGN_LEFT : TXTALIGN_RIGHT ); +} + +void ImpSvMEdit::SetModified( sal_Bool bMod ) +{ + mpTextWindow->GetTextEngine()->SetModified( bMod ); +} + +sal_Bool ImpSvMEdit::IsModified() const +{ + return mpTextWindow->GetTextEngine()->IsModified(); +} + +void ImpSvMEdit::SetReadOnly( sal_Bool bRdOnly ) +{ + mpTextWindow->GetTextView()->SetReadOnly( bRdOnly ); + // Farbe anpassen ??????????????????????????? +} + +sal_Bool ImpSvMEdit::IsReadOnly() const +{ + return mpTextWindow->GetTextView()->IsReadOnly(); +} + +void ImpSvMEdit::SetMaxTextLen( xub_StrLen nLen ) +{ + mpTextWindow->GetTextEngine()->SetMaxTextLen( nLen ); +} + +xub_StrLen ImpSvMEdit::GetMaxTextLen() const +{ + return sal::static_int_cast< xub_StrLen >( + mpTextWindow->GetTextEngine()->GetMaxTextLen()); +} + +void ImpSvMEdit::InsertText( const String& rStr ) +{ + mpTextWindow->GetTextView()->InsertText( rStr ); +} + +String ImpSvMEdit::GetSelected() const +{ + return mpTextWindow->GetTextView()->GetSelected(); +} + +String ImpSvMEdit::GetSelected( LineEnd aSeparator ) const +{ + return mpTextWindow->GetTextView()->GetSelected( aSeparator ); +} + +void ImpSvMEdit::Resize() +{ + size_t nIteration = 1; + do + { + WinBits nWinStyle( pSvVCLMultiLineEdit->GetStyle() ); + if ( ( nWinStyle & WB_AUTOVSCROLL ) == WB_AUTOVSCROLL ) + ImpUpdateSrollBarVis( nWinStyle ); + + Size aSz = pSvVCLMultiLineEdit->GetOutputSizePixel(); + Size aEditSize = aSz; + long nSBWidth = pSvVCLMultiLineEdit->GetSettings().GetStyleSettings().GetScrollBarSize(); + nSBWidth = pSvVCLMultiLineEdit->CalcZoom( nSBWidth ); + + if ( mpHScrollBar ) + aSz.Height() -= nSBWidth+1; + if ( mpVScrollBar ) + aSz.Width() -= nSBWidth+1; + + if ( !mpHScrollBar ) + mpTextWindow->GetTextEngine()->SetMaxTextWidth( aSz.Width() ); + else + mpHScrollBar->SetPosSizePixel( 0, aEditSize.Height()-nSBWidth, aSz.Width(), nSBWidth ); + + Point aTextWindowPos( maTextWindowOffset ); + if ( mpVScrollBar ) + { + if( Application::GetSettings().GetLayoutRTL() ) + { + mpVScrollBar->SetPosSizePixel( 0, 0, nSBWidth, aSz.Height() ); + aTextWindowPos.X() += nSBWidth; + } + else + mpVScrollBar->SetPosSizePixel( aEditSize.Width()-nSBWidth, 0, nSBWidth, aSz.Height() ); + } + + if ( mpScrollBox ) + mpScrollBox->SetPosSizePixel( aSz.Width(), aSz.Height(), nSBWidth, nSBWidth ); + + Size aTextWindowSize( aSz ); + aTextWindowSize.Width() -= maTextWindowOffset.X(); + aTextWindowSize.Height() -= maTextWindowOffset.Y(); + if ( aTextWindowSize.Width() < 0 ) + aTextWindowSize.Width() = 0; + if ( aTextWindowSize.Height() < 0 ) + aTextWindowSize.Height() = 0; + + Size aOldTextWindowSize( mpTextWindow->GetSizePixel() ); + mpTextWindow->SetPosSizePixel( aTextWindowPos, aTextWindowSize ); + if ( aOldTextWindowSize == aTextWindowSize ) + break; + + // Changing the text window size might effectively have changed the need for + // scrollbars, so do another iteration. + ++nIteration; + OSL_ENSURE( nIteration < 3, "ImpSvMEdit::Resize: isn't this expected to terminate with the second iteration?" ); + + } while ( nIteration <= 3 ); // artificial break after four iterations + + ImpInitScrollBars(); +} + +void ImpSvMEdit::GetFocus() +{ + mpTextWindow->GrabFocus(); +} + +void ImpSvMEdit::Cut() +{ + if ( !mpTextWindow->GetTextView()->IsReadOnly() ) + mpTextWindow->GetTextView()->Cut(); +} + +void ImpSvMEdit::Copy() +{ + mpTextWindow->GetTextView()->Copy(); +} + +void ImpSvMEdit::Paste() +{ + if ( !mpTextWindow->GetTextView()->IsReadOnly() ) + mpTextWindow->GetTextView()->Paste(); +} + +void ImpSvMEdit::SetText( const String& rStr ) +{ + sal_Bool bWasModified = mpTextWindow->GetTextEngine()->IsModified(); + mpTextWindow->GetTextEngine()->SetText( rStr ); + if ( !bWasModified ) + mpTextWindow->GetTextEngine()->SetModified( sal_False ); + + mpTextWindow->GetTextView()->SetSelection( TextSelection() ); + + WinBits nWinStyle( pSvVCLMultiLineEdit->GetStyle() ); + if ( ( nWinStyle & WB_AUTOVSCROLL ) == WB_AUTOVSCROLL ) + ImpUpdateSrollBarVis( nWinStyle ); +} + +String ImpSvMEdit::GetText() const +{ + return mpTextWindow->GetTextEngine()->GetText(); +} + +String ImpSvMEdit::GetText( LineEnd aSeparator ) const +{ + return mpTextWindow->GetTextEngine()->GetText( aSeparator ); +} + +String ImpSvMEdit::GetTextLines( LineEnd aSeparator ) const +{ + return mpTextWindow->GetTextEngine()->GetTextLines( aSeparator ); +} + +void ImpSvMEdit::Notify( SfxBroadcaster&, const SfxHint& rHint ) +{ + if ( rHint.ISA( TextHint ) ) + { + const TextHint& rTextHint = (const TextHint&)rHint; + if( rTextHint.GetId() == TEXT_HINT_VIEWSCROLLED ) + { + if ( mpHScrollBar ) + ImpSetHScrollBarThumbPos(); + if ( mpVScrollBar ) + mpVScrollBar->SetThumbPos( mpTextWindow->GetTextView()->GetStartDocPos().Y() ); + } + else if( rTextHint.GetId() == TEXT_HINT_TEXTHEIGHTCHANGED ) + { + if ( mpTextWindow->GetTextView()->GetStartDocPos().Y() ) + { + long nOutHeight = mpTextWindow->GetOutputSizePixel().Height(); + long nTextHeight = mpTextWindow->GetTextEngine()->GetTextHeight(); + if ( nTextHeight < nOutHeight ) + mpTextWindow->GetTextView()->Scroll( 0, mpTextWindow->GetTextView()->GetStartDocPos().Y() ); + } + + ImpSetScrollBarRanges(); + } + else if( rTextHint.GetId() == TEXT_HINT_TEXTFORMATTED ) + { + if ( mpHScrollBar ) + { + sal_uLong nWidth = mpTextWindow->GetTextEngine()->CalcTextWidth(); + if ( nWidth != mnTextWidth ) + { + mnTextWidth = sal::static_int_cast< xub_StrLen >(nWidth); + mpHScrollBar->SetRange( Range( 0, (long)mnTextWidth-1 ) ); + ImpSetHScrollBarThumbPos(); + } + } + } + else if( rTextHint.GetId() == TEXT_HINT_MODIFIED ) + { + pSvVCLMultiLineEdit->Modify(); + } + } +} + +void ImpSvMEdit::SetSelection( const Selection& rSelection ) +{ + String aText = mpTextWindow->GetTextEngine()->GetText(); + + Selection aNewSelection( rSelection ); + if ( aNewSelection.Min() < 0 ) + aNewSelection.Min() = 0; + else if ( aNewSelection.Min() > aText.Len() ) + aNewSelection.Min() = aText.Len(); + if ( aNewSelection.Max() < 0 ) + aNewSelection.Max() = 0; + else if ( aNewSelection.Max() > aText.Len() ) + aNewSelection.Max() = aText.Len(); + + long nEnd = Max( aNewSelection.Min(), aNewSelection.Max() ); + TextSelection aTextSel; + sal_uLong nPara = 0; + sal_uInt16 nChar = 0; + sal_uInt16 x = 0; + while ( x <= nEnd ) + { + if ( x == aNewSelection.Min() ) + aTextSel.GetStart() = TextPaM( nPara, nChar ); + if ( x == aNewSelection.Max() ) + aTextSel.GetEnd() = TextPaM( nPara, nChar ); + + if ( ( x < aText.Len() ) && ( aText.GetChar( x ) == '\n' ) ) + { + nPara++; + nChar = 0; + } + else + nChar++; + x++; + } + mpTextWindow->GetTextView()->SetSelection( aTextSel ); +} + +const Selection& ImpSvMEdit::GetSelection() const +{ + maSelection = Selection(); + TextSelection aTextSel( mpTextWindow->GetTextView()->GetSelection() ); + aTextSel.Justify(); + // Selektion flachklopfen => jeder Umbruch ein Zeichen... + + ExtTextEngine* pTextEngine = mpTextWindow->GetTextEngine(); + // Absaetze davor: + sal_uLong n; + for ( n = 0; n < aTextSel.GetStart().GetPara(); n++ ) + { + maSelection.Min() += pTextEngine->GetTextLen( n ); + maSelection.Min()++; + } + + // Erster Absatz mit Selektion: + maSelection.Max() = maSelection.Min(); + maSelection.Min() += aTextSel.GetStart().GetIndex(); + + for ( n = aTextSel.GetStart().GetPara(); n < aTextSel.GetEnd().GetPara(); n++ ) + { + maSelection.Max() += pTextEngine->GetTextLen( n ); + maSelection.Max()++; + } + + maSelection.Max() += aTextSel.GetEnd().GetIndex(); + + return maSelection; +} + +Size ImpSvMEdit::CalcMinimumSize() const +{ + Size aSz( mpTextWindow->GetTextEngine()->CalcTextWidth(), + mpTextWindow->GetTextEngine()->GetTextHeight() ); + + if ( mpHScrollBar ) + aSz.Height() += mpHScrollBar->GetSizePixel().Height(); + if ( mpVScrollBar ) + aSz.Width() += mpVScrollBar->GetSizePixel().Width(); + + return aSz; +} + +Size ImpSvMEdit::CalcSize( sal_uInt16 nColumns, sal_uInt16 nLines ) const +{ + static const sal_Unicode sampleChar = 'X'; + + Size aSz; + Size aCharSz; + aCharSz.Width() = mpTextWindow->GetTextWidth( rtl::OUString(sampleChar) ); + aCharSz.Height() = mpTextWindow->GetTextHeight(); + + if ( nLines ) + aSz.Height() = nLines*aCharSz.Height(); + else + aSz.Height() = mpTextWindow->GetTextEngine()->GetTextHeight(); + + if ( nColumns ) + aSz.Width() = nColumns*aCharSz.Width(); + else + aSz.Width() = mpTextWindow->GetTextEngine()->CalcTextWidth(); + + if ( mpHScrollBar ) + aSz.Height() += mpHScrollBar->GetSizePixel().Height(); + if ( mpVScrollBar ) + aSz.Width() += mpVScrollBar->GetSizePixel().Width(); + + return aSz; +} + +void ImpSvMEdit::GetMaxVisColumnsAndLines( sal_uInt16& rnCols, sal_uInt16& rnLines ) const +{ + static const sal_Unicode sampleChar = { 'x' }; + Size aOutSz = mpTextWindow->GetOutputSizePixel(); + Size aCharSz( mpTextWindow->GetTextWidth( rtl::OUString(sampleChar) ), mpTextWindow->GetTextHeight() ); + rnCols = (sal_uInt16) (aOutSz.Width()/aCharSz.Width()); + rnLines = (sal_uInt16) (aOutSz.Height()/aCharSz.Height()); +} + +void ImpSvMEdit::Enable( sal_Bool bEnable ) +{ + mpTextWindow->Enable( bEnable ); + if ( mpHScrollBar ) + mpHScrollBar->Enable( bEnable ); + if ( mpVScrollBar ) + mpVScrollBar->Enable( bEnable ); +} + +sal_Bool ImpSvMEdit::HandleCommand( const CommandEvent& rCEvt ) +{ + sal_Bool bDone = sal_False; + if ( ( rCEvt.GetCommand() == COMMAND_WHEEL ) || + ( rCEvt.GetCommand() == COMMAND_STARTAUTOSCROLL ) || + ( rCEvt.GetCommand() == COMMAND_AUTOSCROLL ) ) + { + mpTextWindow->HandleScrollCommand( rCEvt, mpHScrollBar, mpVScrollBar ); + bDone = sal_True; + } + return bDone; +} + + +TextWindow::TextWindow( Window* pParent ) : Window( pParent ) +{ + mbInMBDown = sal_False; + mbSelectOnTab = sal_True; + mbFocusSelectionHide = sal_False; + mbIgnoreTab = sal_False; + mbActivePopup = sal_False; + mbSelectOnTab = sal_True; + mbTextSelectable = sal_True; + + SetPointer( Pointer( POINTER_TEXT ) ); + + mpTextEngine = new ExtTextEngine; + mpTextEngine->SetMaxTextLen( STRING_MAXLEN ); + if( pParent->GetStyle() & WB_BORDER ) + mpTextEngine->SetLeftMargin( 2 ); + mpTextEngine->SetLocale( GetSettings().GetLocale() ); + mpTextView = new ExtTextView( mpTextEngine, this ); + mpTextEngine->InsertView( mpTextView ); + mpTextEngine->EnableUndo( sal_True ); + mpTextView->ShowCursor(); + + Color aBackgroundColor = GetSettings().GetStyleSettings().GetWorkspaceColor(); + SetBackground( aBackgroundColor ); + pParent->SetBackground( aBackgroundColor ); +} + +TextWindow::~TextWindow() +{ + delete mpTextView; + delete mpTextEngine; +} + +void TextWindow::MouseMove( const MouseEvent& rMEvt ) +{ + mpTextView->MouseMove( rMEvt ); + Window::MouseMove( rMEvt ); +} + +void TextWindow::MouseButtonDown( const MouseEvent& rMEvt ) +{ + if ( !mbTextSelectable ) + return; + + mbInMBDown = sal_True; // Dann im GetFocus nicht alles selektieren wird + mpTextView->MouseButtonDown( rMEvt ); + Window::MouseButtonDown( rMEvt ); + GrabFocus(); + mbInMBDown = sal_False; +} + +void TextWindow::MouseButtonUp( const MouseEvent& rMEvt ) +{ + mpTextView->MouseButtonUp( rMEvt ); + Window::MouseButtonUp( rMEvt ); +} + +void TextWindow::KeyInput( const KeyEvent& rKEvent ) +{ + sal_Bool bDone = sal_False; + sal_uInt16 nCode = rKEvent.GetKeyCode().GetCode(); + if ( nCode == com::sun::star::awt::Key::SELECT_ALL || + ( (nCode == KEY_A) && rKEvent.GetKeyCode().IsMod1() && !rKEvent.GetKeyCode().IsMod2() ) + ) + { + mpTextView->SetSelection( TextSelection( TextPaM( 0, 0 ), TextPaM( 0xFFFF, 0xFFFF ) ) ); + bDone = sal_True; + } + else if ( (nCode == KEY_S) && rKEvent.GetKeyCode().IsShift() && rKEvent.GetKeyCode().IsMod1() ) + { + if ( Edit::GetGetSpecialCharsFunction() ) + { + // Damit die Selektion erhalten bleibt + mbActivePopup = sal_True; + rtl::OUString aChars = Edit::GetGetSpecialCharsFunction()( this, GetFont() ); + if (!aChars.isEmpty()) + { + mpTextView->InsertText( aChars ); + mpTextView->GetTextEngine()->SetModified( sal_True ); + } + mbActivePopup = sal_False; + bDone = sal_True; + } + } + else if ( nCode == KEY_TAB ) + { + if ( !mbIgnoreTab || rKEvent.GetKeyCode().IsMod1() ) + bDone = mpTextView->KeyInput( rKEvent ); + } + else + { + bDone = mpTextView->KeyInput( rKEvent ); + } + + if ( !bDone ) + Window::KeyInput( rKEvent ); +} + +void TextWindow::Paint( const Rectangle& rRect ) +{ + mpTextView->Paint( rRect ); +} + +void TextWindow::Resize() +{ +} + +void TextWindow::Command( const CommandEvent& rCEvt ) +{ + if ( rCEvt.GetCommand() == COMMAND_CONTEXTMENU ) + { + PopupMenu* pPopup = Edit::CreatePopupMenu(); + if ( !mpTextView->HasSelection() ) + { + pPopup->EnableItem( SV_MENU_EDIT_CUT, sal_False ); + pPopup->EnableItem( SV_MENU_EDIT_COPY, sal_False ); + pPopup->EnableItem( SV_MENU_EDIT_DELETE, sal_False ); + } + if ( mpTextView->IsReadOnly() ) + { + pPopup->EnableItem( SV_MENU_EDIT_CUT, sal_False ); + pPopup->EnableItem( SV_MENU_EDIT_PASTE, sal_False ); + pPopup->EnableItem( SV_MENU_EDIT_DELETE, sal_False ); + pPopup->EnableItem( SV_MENU_EDIT_INSERTSYMBOL, sal_False ); + } + if ( !mpTextView->GetTextEngine()->HasUndoManager() || !mpTextView->GetTextEngine()->GetUndoManager().GetUndoActionCount() ) + { + pPopup->EnableItem( SV_MENU_EDIT_UNDO, sal_False ); + } +// if ( ( maSelection.Min() == 0 ) && ( maSelection.Max() == maText.Len() ) ) +// { +// pPopup->EnableItem( SV_MENU_EDIT_SELECTALL, sal_False ); +// } + if ( !Edit::GetGetSpecialCharsFunction() ) + { + sal_uInt16 nPos = pPopup->GetItemPos( SV_MENU_EDIT_INSERTSYMBOL ); + pPopup->RemoveItem( nPos ); + pPopup->RemoveItem( nPos-1 ); + } + + mbActivePopup = sal_True; + Point aPos = rCEvt.GetMousePosPixel(); + if ( !rCEvt.IsMouseEvent() ) + { + // !!! Irgendwann einmal Menu zentriert in der Selektion anzeigen !!! + Size aSize = GetOutputSizePixel(); + aPos = Point( aSize.Width()/2, aSize.Height()/2 ); + } +// pPopup->RemoveDisabledEntries(); + sal_uInt16 n = pPopup->Execute( this, aPos ); + Edit::DeletePopupMenu( pPopup ); + switch ( n ) + { + case SV_MENU_EDIT_UNDO: mpTextView->Undo(); + mpTextEngine->SetModified( sal_True ); + mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) ); + break; + case SV_MENU_EDIT_CUT: mpTextView->Cut(); + mpTextEngine->SetModified( sal_True ); + mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) ); + break; + case SV_MENU_EDIT_COPY: mpTextView->Copy(); + break; + case SV_MENU_EDIT_PASTE: mpTextView->Paste(); + mpTextEngine->SetModified( sal_True ); + mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) ); + break; + case SV_MENU_EDIT_DELETE: mpTextView->DeleteSelected(); + mpTextEngine->SetModified( sal_True ); + mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) ); + break; + case SV_MENU_EDIT_SELECTALL: mpTextView->SetSelection( TextSelection( TextPaM( 0, 0 ), TextPaM( 0xFFFFFFFF, 0xFFFF ) ) ); + break; + case SV_MENU_EDIT_INSERTSYMBOL: + { + rtl::OUString aChars = Edit::GetGetSpecialCharsFunction()( this, GetFont() ); + if (!aChars.isEmpty()) + { + mpTextView->InsertText( aChars ); + mpTextEngine->SetModified( sal_True ); + mpTextEngine->Broadcast( TextHint( TEXT_HINT_MODIFIED ) ); + } + } + break; + } + mbActivePopup = sal_False; + } + else + { + mpTextView->Command( rCEvt ); + } + Window::Command( rCEvt ); +} + +void TextWindow::GetFocus() +{ + Window::GetFocus(); + if ( !mbActivePopup ) + { + sal_Bool bGotoCursor = !mpTextView->IsReadOnly(); + if ( mbFocusSelectionHide && IsReallyVisible() && !mpTextView->IsReadOnly() + && ( mbSelectOnTab && + (!mbInMBDown || ( GetSettings().GetStyleSettings().GetSelectionOptions() & SELECTION_OPTION_FOCUS ) )) ) + { + // Alles selektieren, aber nicht scrollen + sal_Bool bAutoScroll = mpTextView->IsAutoScroll(); + mpTextView->SetAutoScroll( sal_False ); + mpTextView->SetSelection( TextSelection( TextPaM( 0, 0 ), TextPaM( 0xFFFF, 0xFFFF ) ) ); + mpTextView->SetAutoScroll( bAutoScroll ); + bGotoCursor = sal_False; + } + mpTextView->SetPaintSelection( sal_True ); + mpTextView->ShowCursor( bGotoCursor ); + } +} + +void TextWindow::LoseFocus() +{ + Window::LoseFocus(); + + if ( mbFocusSelectionHide && !mbActivePopup ) + mpTextView->SetPaintSelection( sal_False ); +} + +VCLMultiLineEdit::VCLMultiLineEdit( Window* pParent, WinBits nWinStyle ) + : Edit( pParent, nWinStyle ) +{ + SetType( WINDOW_MULTILINEEDIT ); + pImpSvMEdit = new ImpSvMEdit( this, nWinStyle ); + ImplInitSettings( sal_True, sal_True, sal_True ); + pUpdateDataTimer = 0; + + SetCompoundControl( sal_True ); + SetStyle( ImplInitStyle( nWinStyle ) ); +} + +VCLMultiLineEdit::VCLMultiLineEdit( Window* pParent, const ResId& rResId ) + : Edit( pParent, rResId.SetRT( RSC_MULTILINEEDIT ) ) +{ + SetType( WINDOW_MULTILINEEDIT ); + WinBits nWinStyle = rResId.GetWinBits(); + pImpSvMEdit = new ImpSvMEdit( this, nWinStyle ); + ImplInitSettings( sal_True, sal_True, sal_True ); + pUpdateDataTimer = 0; + + sal_uInt16 nMaxLen = Edit::GetMaxTextLen(); + if ( nMaxLen ) + SetMaxTextLen( nMaxLen ); + + SetText( Edit::GetText() ); + + if ( IsVisible() ) + pImpSvMEdit->Resize(); + + SetCompoundControl( sal_True ); + SetStyle( ImplInitStyle( nWinStyle ) ); + + // Base Edit ctor could call Show already, but that would cause problems + // with accessibility, as Show might (indirectly) trigger a call to virtual + // GetComponentInterface, which is the Edit's base version instead of the + // VCLMultiLineEdit's version while in the base Edit ctor: + if ((GetStyle() & WB_HIDE) == 0) + Show(); + +} + +VCLMultiLineEdit::~VCLMultiLineEdit() +{ + { + ::std::auto_ptr< ImpSvMEdit > pDelete( pImpSvMEdit ); + pImpSvMEdit = NULL; + } + delete pUpdateDataTimer; +} + +WinBits VCLMultiLineEdit::ImplInitStyle( WinBits nStyle ) +{ + if ( !(nStyle & WB_NOTABSTOP) ) + nStyle |= WB_TABSTOP; + + if ( !(nStyle & WB_NOGROUP) ) + nStyle |= WB_GROUP; + + if ( !(nStyle & WB_IGNORETAB )) + nStyle |= WINDOW_DLGCTRL_MOD1TAB; + + return nStyle; +} + + +void VCLMultiLineEdit::ImplInitSettings( sal_Bool /*bFont*/, sal_Bool /*bForeground*/, sal_Bool bBackground ) +{ + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + // Der Font muss immer mit manipuliert werden, weil die TextEngine + // sich nicht um TextColor/Background kuemmert + + Color aTextColor = rStyleSettings.GetFieldTextColor(); + if ( IsControlForeground() ) + aTextColor = GetControlForeground(); + if ( !IsEnabled() ) + aTextColor = rStyleSettings.GetDisableColor(); + + Font aFont = rStyleSettings.GetFieldFont(); + if ( IsControlFont() ) + aFont.Merge( GetControlFont() ); + aFont.SetTransparent( IsPaintTransparent() ); + SetZoomedPointFont( aFont ); + Font TheFont = GetFont(); + TheFont.SetColor( aTextColor ); + if( IsPaintTransparent() ) + TheFont.SetFillColor( Color( COL_TRANSPARENT ) ); + else + TheFont.SetFillColor( IsControlBackground() ? GetControlBackground() : rStyleSettings.GetFieldColor() ); + pImpSvMEdit->GetTextWindow()->SetFont( TheFont ); + pImpSvMEdit->GetTextWindow()->GetTextEngine()->SetFont( TheFont ); + pImpSvMEdit->GetTextWindow()->SetTextColor( aTextColor ); + + if ( bBackground ) + { + if( IsPaintTransparent() ) + { + pImpSvMEdit->GetTextWindow()->SetPaintTransparent( sal_True ); + pImpSvMEdit->GetTextWindow()->SetBackground(); + pImpSvMEdit->GetTextWindow()->SetControlBackground(); + SetBackground(); + SetControlBackground(); + } + else + { + if( IsControlBackground() ) + pImpSvMEdit->GetTextWindow()->SetBackground( GetControlBackground() ); + else + pImpSvMEdit->GetTextWindow()->SetBackground( rStyleSettings.GetFieldColor() ); + // Auch am VCLMultiLineEdit einstellen, weil die TextComponent + // ggf. die Scrollbars hidet. + SetBackground( pImpSvMEdit->GetTextWindow()->GetBackground() ); + } + } +} + +void VCLMultiLineEdit::Modify() +{ + aModifyHdlLink.Call( this ); + + CallEventListeners( VCLEVENT_EDIT_MODIFY ); + + if ( pUpdateDataTimer ) + pUpdateDataTimer->Start(); +} + +IMPL_LINK_NOARG(VCLMultiLineEdit, ImpUpdateDataHdl) +{ + UpdateData(); + return 0; +} + +void VCLMultiLineEdit::UpdateData() +{ + aUpdateDataHdlLink.Call( this ); +} + +void VCLMultiLineEdit::SetModifyFlag() +{ + pImpSvMEdit->SetModified( sal_True ); +} + +void VCLMultiLineEdit::ClearModifyFlag() +{ + pImpSvMEdit->SetModified( sal_False ); +} + +sal_Bool VCLMultiLineEdit::IsModified() const +{ + return pImpSvMEdit->IsModified(); +} + +void VCLMultiLineEdit::EnableUpdateData( sal_uLong nTimeout ) +{ + if ( !nTimeout ) + DisableUpdateData(); + else + { + if ( !pUpdateDataTimer ) + { + pUpdateDataTimer = new Timer; + pUpdateDataTimer->SetTimeoutHdl( LINK( this, VCLMultiLineEdit, ImpUpdateDataHdl ) ); + } + pUpdateDataTimer->SetTimeout( nTimeout ); + } +} + +void VCLMultiLineEdit::SetReadOnly( sal_Bool bReadOnly ) +{ + pImpSvMEdit->SetReadOnly( bReadOnly ); + Edit::SetReadOnly( bReadOnly ); + + // #94921# ReadOnly can be overwritten in InitFromStyle() when WB not set. + WinBits nStyle = GetStyle(); + if ( bReadOnly ) + nStyle |= WB_READONLY; + else + nStyle &= ~WB_READONLY; + SetStyle( nStyle ); +} + +sal_Bool VCLMultiLineEdit::IsReadOnly() const +{ + return pImpSvMEdit->IsReadOnly(); +} + +void VCLMultiLineEdit::SetMaxTextLen( xub_StrLen nMaxLen ) +{ + pImpSvMEdit->SetMaxTextLen( nMaxLen ); +} + +xub_StrLen VCLMultiLineEdit::GetMaxTextLen() const +{ + return pImpSvMEdit->GetMaxTextLen(); +} + +void VCLMultiLineEdit::ReplaceSelected( const String& rStr ) +{ + pImpSvMEdit->InsertText( rStr ); +} + +void VCLMultiLineEdit::DeleteSelected() +{ + pImpSvMEdit->InsertText( String() ); +} + +String VCLMultiLineEdit::GetSelected() const +{ + return pImpSvMEdit->GetSelected(); +} + +String VCLMultiLineEdit::GetSelected( LineEnd aSeparator ) const +{ + return pImpSvMEdit->GetSelected( aSeparator ); +} + +void VCLMultiLineEdit::Cut() +{ + pImpSvMEdit->Cut(); +} + +void VCLMultiLineEdit::Copy() +{ + pImpSvMEdit->Copy(); +} + +void VCLMultiLineEdit::Paste() +{ + pImpSvMEdit->Paste(); +} + +void VCLMultiLineEdit::SetText( const String& rStr ) +{ + pImpSvMEdit->SetText( rStr ); +} + +String VCLMultiLineEdit::GetText() const +{ + return pImpSvMEdit->GetText(); +} + +String VCLMultiLineEdit::GetText( LineEnd aSeparator ) const +{ + return pImpSvMEdit->GetText( aSeparator ); +} + +String VCLMultiLineEdit::GetTextLines( LineEnd aSeparator ) const +{ + return pImpSvMEdit->GetTextLines( aSeparator ); +} + +void VCLMultiLineEdit::Resize() +{ + pImpSvMEdit->Resize(); +} + +void VCLMultiLineEdit::GetFocus() +{ + if ( !pImpSvMEdit ) // might be called from within the dtor, when pImpSvMEdit == NULL is a valid state + return; + + Edit::GetFocus(); + pImpSvMEdit->GetFocus(); +} + +void VCLMultiLineEdit::SetSelection( const Selection& rSelection ) +{ + pImpSvMEdit->SetSelection( rSelection ); +} + +const Selection& VCLMultiLineEdit::GetSelection() const +{ + return pImpSvMEdit->GetSelection(); +} + +Size VCLMultiLineEdit::CalcMinimumSize() const +{ + Size aSz = pImpSvMEdit->CalcMinimumSize(); + + sal_Int32 nLeft, nTop, nRight, nBottom; + ((Window*)this)->GetBorder( nLeft, nTop, nRight, nBottom ); + aSz.Width() += nLeft+nRight; + aSz.Height() += nTop+nBottom; + + return aSz; +} + +Size VCLMultiLineEdit::CalcAdjustedSize( const Size& rPrefSize ) const +{ + Size aSz = rPrefSize; + sal_Int32 nLeft, nTop, nRight, nBottom; + ((Window*)this)->GetBorder( nLeft, nTop, nRight, nBottom ); + + // In der Hoehe auf ganze Zeilen justieren + + long nHeight = aSz.Height() - nTop - nBottom; + long nLineHeight = pImpSvMEdit->CalcSize( 1, 1 ).Height(); + long nLines = nHeight / nLineHeight; + if ( nLines < 1 ) + nLines = 1; + + aSz.Height() = nLines * nLineHeight; + aSz.Height() += nTop+nBottom; + + return aSz; +} + +Size VCLMultiLineEdit::CalcSize( sal_uInt16 nColumns, sal_uInt16 nLines ) const +{ + Size aSz = pImpSvMEdit->CalcSize( nColumns, nLines ); + + sal_Int32 nLeft, nTop, nRight, nBottom; + ((Window*)this)->GetBorder( nLeft, nTop, nRight, nBottom ); + aSz.Width() += nLeft+nRight; + aSz.Height() += nTop+nBottom; + return aSz; +} + +void VCLMultiLineEdit::GetMaxVisColumnsAndLines( sal_uInt16& rnCols, sal_uInt16& rnLines ) const +{ + pImpSvMEdit->GetMaxVisColumnsAndLines( rnCols, rnLines ); +} + +void VCLMultiLineEdit::StateChanged( StateChangedType nType ) +{ + if( nType == STATE_CHANGE_ENABLE ) + { + pImpSvMEdit->Enable( IsEnabled() ); + ImplInitSettings( sal_True, sal_False, sal_False ); + } + else if( nType == STATE_CHANGE_READONLY ) + { + pImpSvMEdit->SetReadOnly( IsReadOnly() ); + } + else if ( nType == STATE_CHANGE_ZOOM ) + { + pImpSvMEdit->GetTextWindow()->SetZoom( GetZoom() ); + ImplInitSettings( sal_True, sal_False, sal_False ); + Resize(); + } + else if ( nType == STATE_CHANGE_CONTROLFONT ) + { + ImplInitSettings( sal_True, sal_False, sal_False ); + Resize(); + Invalidate(); + } + else if ( nType == STATE_CHANGE_CONTROLFOREGROUND ) + { + ImplInitSettings( sal_False, sal_True, sal_False ); + Invalidate(); + } + else if ( nType == STATE_CHANGE_CONTROLBACKGROUND ) + { + ImplInitSettings( sal_False, sal_False, sal_True ); + Invalidate(); + } + else if ( nType == STATE_CHANGE_STYLE ) + { + pImpSvMEdit->InitFromStyle( GetStyle() ); + SetStyle( ImplInitStyle( GetStyle() ) ); + } + else if ( nType == STATE_CHANGE_INITSHOW ) + { + if( IsPaintTransparent() ) + { + pImpSvMEdit->GetTextWindow()->SetPaintTransparent( sal_True ); + pImpSvMEdit->GetTextWindow()->SetBackground(); + pImpSvMEdit->GetTextWindow()->SetControlBackground(); + SetBackground(); + SetControlBackground(); + } + } + + Control::StateChanged( nType ); +} + +void VCLMultiLineEdit::DataChanged( const DataChangedEvent& rDCEvt ) +{ + if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && + (rDCEvt.GetFlags() & SETTINGS_STYLE) ) + { + ImplInitSettings( sal_True, sal_True, sal_True ); + Resize(); + Invalidate(); + } + else + Control::DataChanged( rDCEvt ); +} + +void VCLMultiLineEdit::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, sal_uLong nFlags ) +{ + ImplInitSettings( sal_True, sal_True, sal_True ); + + Point aPos = pDev->LogicToPixel( rPos ); + Size aSize = pDev->LogicToPixel( rSize ); + Font aFont = pImpSvMEdit->GetTextWindow()->GetDrawPixelFont( pDev ); + aFont.SetTransparent( sal_True ); + OutDevType eOutDevType = pDev->GetOutDevType(); + + pDev->Push(); + pDev->SetMapMode(); + pDev->SetFont( aFont ); + pDev->SetTextFillColor(); + + // Border/Background + pDev->SetLineColor(); + pDev->SetFillColor(); + sal_Bool bBorder = !(nFlags & WINDOW_DRAW_NOBORDER ) && (GetStyle() & WB_BORDER); + sal_Bool bBackground = !(nFlags & WINDOW_DRAW_NOBACKGROUND) && IsControlBackground(); + if ( bBorder || bBackground ) + { + Rectangle aRect( aPos, aSize ); + if ( bBorder ) + { + DecorationView aDecoView( pDev ); + aRect = aDecoView.DrawFrame( aRect, FRAME_DRAW_DOUBLEIN ); + } + if ( bBackground ) + { + pDev->SetFillColor( GetControlBackground() ); + pDev->DrawRect( aRect ); + } + } + + // Inhalt + if ( ( nFlags & WINDOW_DRAW_MONO ) || ( eOutDevType == OUTDEV_PRINTER ) ) + pDev->SetTextColor( Color( COL_BLACK ) ); + else + { + if ( !(nFlags & WINDOW_DRAW_NODISABLE ) && !IsEnabled() ) + { + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + pDev->SetTextColor( rStyleSettings.GetDisableColor() ); + } + else + { + pDev->SetTextColor( GetTextColor() ); + } + } + + rtl::OUString aText = GetText(); + Size aTextSz( pDev->GetTextWidth( aText ), pDev->GetTextHeight() ); + sal_uLong nLines = (sal_uLong) (aSize.Height() / aTextSz.Height()); + if ( !nLines ) + nLines = 1; + aTextSz.Height() = nLines*aTextSz.Height(); + long nOnePixel = GetDrawPixel( pDev, 1 ); + long nOffX = 3*nOnePixel; + long nOffY = 2*nOnePixel; + + // Clipping? + if ( ( nOffY < 0 ) || ( (nOffY+aTextSz.Height()) > aSize.Height() ) || ( (nOffX+aTextSz.Width()) > aSize.Width() ) ) + { + Rectangle aClip( aPos, aSize ); + if ( aTextSz.Height() > aSize.Height() ) + aClip.Bottom() += aTextSz.Height() - aSize.Height() + 1; // Damit HP-Drucker nicht 'weg-optimieren' + pDev->IntersectClipRegion( aClip ); + } + + ExtTextEngine aTE; + aTE.SetText( GetText() ); + aTE.SetMaxTextWidth( aSize.Width() ); + aTE.SetFont( aFont ); + aTE.SetTextAlign( pImpSvMEdit->GetTextWindow()->GetTextEngine()->GetTextAlign() ); + aTE.Draw( pDev, Point( aPos.X() + nOffX, aPos.Y() + nOffY ) ); + + pDev->Pop(); +} + +long VCLMultiLineEdit::Notify( NotifyEvent& rNEvt ) +{ + long nDone = 0; + if( rNEvt.GetType() == EVENT_COMMAND ) + { + nDone = pImpSvMEdit->HandleCommand( *rNEvt.GetCommandEvent() ); + } + return nDone ? nDone : Edit::Notify( rNEvt ); +} + +long VCLMultiLineEdit::PreNotify( NotifyEvent& rNEvt ) +{ + long nDone = 0; + +#if (OSL_DEBUG_LEVEL > 1) && defined(DBG_UTIL) + if( rNEvt.GetType() == EVENT_KEYINPUT ) + { + const KeyEvent& rKEvent = *rNEvt.GetKeyEvent(); + if ( ( rKEvent.GetKeyCode().GetCode() == KEY_W ) && rKEvent.GetKeyCode().IsMod1() && rKEvent.GetKeyCode().IsMod2() ) + { + SetRightToLeft( !IsRightToLeft() ); + } + } +#endif + + if( ( rNEvt.GetType() == EVENT_KEYINPUT ) && ( !GetTextView()->IsCursorEnabled() ) ) + { + const KeyEvent& rKEvent = *rNEvt.GetKeyEvent(); + if ( !rKEvent.GetKeyCode().IsShift() && ( rKEvent.GetKeyCode().GetGroup() == KEYGROUP_CURSOR ) ) + { + nDone = 1; + TextSelection aSel = pImpSvMEdit->GetTextWindow()->GetTextView()->GetSelection(); + if ( aSel.HasRange() ) + { + aSel.GetStart() = aSel.GetEnd(); + pImpSvMEdit->GetTextWindow()->GetTextView()->SetSelection( aSel ); + } + else + { + switch ( rKEvent.GetKeyCode().GetCode() ) + { + case KEY_UP: + { + if ( pImpSvMEdit->GetVScrollBar() ) + pImpSvMEdit->GetVScrollBar()->DoScrollAction( SCROLL_LINEUP ); + } + break; + case KEY_DOWN: + { + if ( pImpSvMEdit->GetVScrollBar() ) + pImpSvMEdit->GetVScrollBar()->DoScrollAction( SCROLL_LINEDOWN ); + } + break; + case KEY_PAGEUP : + { + if ( pImpSvMEdit->GetVScrollBar() ) + pImpSvMEdit->GetVScrollBar()->DoScrollAction( SCROLL_PAGEUP ); + } + break; + case KEY_PAGEDOWN: + { + if ( pImpSvMEdit->GetVScrollBar() ) + pImpSvMEdit->GetVScrollBar()->DoScrollAction( SCROLL_PAGEDOWN ); + } + break; + case KEY_LEFT: + { + if ( pImpSvMEdit->GetHScrollBar() ) + pImpSvMEdit->GetHScrollBar()->DoScrollAction( SCROLL_LINEUP ); + } + break; + case KEY_RIGHT: + { + if ( pImpSvMEdit->GetHScrollBar() ) + pImpSvMEdit->GetHScrollBar()->DoScrollAction( SCROLL_LINEDOWN ); + } + break; + case KEY_HOME: + { + if ( rKEvent.GetKeyCode().IsMod1() ) + pImpSvMEdit->GetTextWindow()->GetTextView()-> + SetSelection( TextSelection( TextPaM( 0, 0 ) ) ); + } + break; + case KEY_END: + { + if ( rKEvent.GetKeyCode().IsMod1() ) + pImpSvMEdit->GetTextWindow()->GetTextView()-> + SetSelection( TextSelection( TextPaM( 0xFFFF, 0xFFFF ) ) ); + } + break; + default: + { + nDone = 0; + } + } + } + } + } + + return nDone ? nDone : Edit::PreNotify( rNEvt ); +} + +// +// Internas fuer abgeleitete Klassen, z.B. TextComponent + +ExtTextEngine* VCLMultiLineEdit::GetTextEngine() const +{ + return pImpSvMEdit->GetTextWindow()->GetTextEngine(); +} + +ExtTextView* VCLMultiLineEdit::GetTextView() const +{ + return pImpSvMEdit->GetTextWindow()->GetTextView(); +} + +ScrollBar* VCLMultiLineEdit::GetVScrollBar() const +{ + return pImpSvMEdit->GetVScrollBar(); +} + +void VCLMultiLineEdit::EnableFocusSelectionHide( sal_Bool bHide ) +{ + pImpSvMEdit->GetTextWindow()->SetAutoFocusHide( bHide ); +} + +void VCLMultiLineEdit::SetLeftMargin( sal_uInt16 n ) +{ + if ( GetTextEngine() ) + GetTextEngine()->SetLeftMargin( n ); +} + +void VCLMultiLineEdit::SetRightToLeft( sal_Bool bRightToLeft ) +{ + if ( GetTextEngine() ) + { + GetTextEngine()->SetRightToLeft( bRightToLeft ); + GetTextView()->ShowCursor(); + } +} + +sal_Bool VCLMultiLineEdit::IsRightToLeft() const +{ + sal_Bool bRightToLeft = sal_False; + + if ( GetTextEngine() ) + bRightToLeft = GetTextEngine()->IsRightToLeft(); + + return bRightToLeft; +} + +void VCLMultiLineEdit::DisableSelectionOnFocus() +{ + pImpSvMEdit->GetTextWindow()->DisableSelectionOnFocus(); +} + +void VCLMultiLineEdit::SetTextSelectable( sal_Bool bTextSelectable ) +{ + pImpSvMEdit->GetTextWindow()->SetTextSelectable( bTextSelectable ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/edit/xtextedt.cxx b/vcl/source/edit/xtextedt.cxx new file mode 100644 index 0000000..c434ad0 --- /dev/null +++ b/vcl/source/edit/xtextedt.cxx @@ -0,0 +1,421 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include +#include // International +#include +#include +#include + +using namespace ::com::sun::star; + + + +// ------------------------------------------------------------------------- +// class ExtTextEngine +// ------------------------------------------------------------------------- +ExtTextEngine::ExtTextEngine() : maGroupChars(rtl::OUString("(){}[]")) +{ +} + +ExtTextEngine::~ExtTextEngine() +{ +} + +TextSelection ExtTextEngine::MatchGroup( const TextPaM& rCursor ) const +{ + TextSelection aSel( rCursor ); + sal_uInt16 nPos = rCursor.GetIndex(); + sal_uLong nPara = rCursor.GetPara(); + sal_uLong nParas = GetParagraphCount(); + if ( ( nPara < nParas ) && ( nPos < GetTextLen( nPara ) ) ) + { + sal_uInt16 nMatchChar = maGroupChars.Search( GetText( rCursor.GetPara() ).GetChar( nPos ) ); + if ( nMatchChar != STRING_NOTFOUND ) + { + if ( ( nMatchChar % 2 ) == 0 ) + { + // Vorwaerts suchen... + sal_Unicode nSC = maGroupChars.GetChar( nMatchChar ); + sal_Unicode nEC = maGroupChars.GetChar( nMatchChar+1 ); + + sal_uInt16 nCur = nPos+1; + sal_uInt16 nLevel = 1; + while ( nLevel && ( nPara < nParas ) ) + { + XubString aStr = GetText( nPara ); + while ( nCur < aStr.Len() ) + { + if ( aStr.GetChar( nCur ) == nSC ) + nLevel++; + else if ( aStr.GetChar( nCur ) == nEC ) + { + nLevel--; + if ( !nLevel ) + break; // while nCur... + } + nCur++; + } + + if ( nLevel ) + { + nPara++; + nCur = 0; + } + } + if ( nLevel == 0 ) // gefunden + { + aSel.GetStart() = rCursor; + aSel.GetEnd() = TextPaM( nPara, nCur+1 ); + } + } + else + { + // Rueckwaerts suchen... + xub_Unicode nEC = maGroupChars.GetChar( nMatchChar ); + xub_Unicode nSC = maGroupChars.GetChar( nMatchChar-1 ); + + sal_uInt16 nCur = rCursor.GetIndex()-1; + sal_uInt16 nLevel = 1; + while ( nLevel ) + { + if ( GetTextLen( nPara ) ) + { + XubString aStr = GetText( nPara ); + while ( nCur ) + { + if ( aStr.GetChar( nCur ) == nSC ) + { + nLevel--; + if ( !nLevel ) + break; // while nCur... + } + else if ( aStr.GetChar( nCur ) == nEC ) + nLevel++; + + nCur--; + } + } + + if ( nLevel ) + { + if ( nPara ) + { + nPara--; + nCur = GetTextLen( nPara )-1; // egal ob negativ, weil if Len() + } + else + break; + } + } + + if ( nLevel == 0 ) // gefunden + { + aSel.GetStart() = rCursor; + aSel.GetStart().GetIndex()++; // hinter das Zeichen + aSel.GetEnd() = TextPaM( nPara, nCur ); + } + } + } + } + return aSel; +} + +sal_Bool ExtTextEngine::Search( TextSelection& rSel, const util::SearchOptions& rSearchOptions, sal_Bool bForward ) +{ + TextSelection aSel( rSel ); + aSel.Justify(); + + sal_Bool bSearchInSelection = (0 != (rSearchOptions.searchFlag & util::SearchFlags::REG_NOT_BEGINOFLINE) ); + + TextPaM aStartPaM( aSel.GetEnd() ); + if ( aSel.HasRange() && ( ( bSearchInSelection && bForward ) || ( !bSearchInSelection && !bForward ) ) ) + { + aStartPaM = aSel.GetStart(); + } + + bool bFound = false; + sal_uLong nStartNode, nEndNode; + + if ( bSearchInSelection ) + nEndNode = bForward ? aSel.GetEnd().GetPara() : aSel.GetStart().GetPara(); + else + nEndNode = bForward ? (GetParagraphCount()-1) : 0; + + nStartNode = aStartPaM.GetPara(); + + util::SearchOptions aOptions( rSearchOptions ); + aOptions.Locale = Application::GetSettings().GetLocale(); + utl::TextSearch aSearcher( rSearchOptions ); + + // ueber die Absaetze iterieren... + for ( sal_uLong nNode = nStartNode; + bForward ? ( nNode <= nEndNode) : ( nNode >= nEndNode ); + bForward ? nNode++ : nNode-- ) + { + String aText = GetText( nNode ); + sal_uInt16 nStartPos = 0; + sal_uInt16 nEndPos = aText.Len(); + if ( nNode == nStartNode ) + { + if ( bForward ) + nStartPos = aStartPaM.GetIndex(); + else + nEndPos = aStartPaM.GetIndex(); + } + if ( ( nNode == nEndNode ) && bSearchInSelection ) + { + if ( bForward ) + nEndPos = aSel.GetEnd().GetIndex(); + else + nStartPos = aSel.GetStart().GetIndex(); + } + + if ( bForward ) + bFound = aSearcher.SearchFrwrd( aText, &nStartPos, &nEndPos ); + else + bFound = aSearcher.SearchBkwrd( aText, &nEndPos, &nStartPos ); + + if ( bFound ) + { + rSel.GetStart().GetPara() = nNode; + rSel.GetStart().GetIndex() = nStartPos; + rSel.GetEnd().GetPara() = nNode; + rSel.GetEnd().GetIndex() = nEndPos; + // Ueber den Absatz selektieren? + // Select over the paragraph? + // FIXME This should be max long... + if( nEndPos == sal::static_int_cast(-1) ) // sal_uInt16 for 0 and -1 ! + { + if ( (rSel.GetEnd().GetPara()+1) < GetParagraphCount() ) + { + rSel.GetEnd().GetPara()++; + rSel.GetEnd().GetIndex() = 0; + } + else + { + rSel.GetEnd().GetIndex() = nStartPos; + bFound = false; + } + } + + break; + } + + if ( !bForward && !nNode ) // Bei rueckwaertsuche, wenn nEndNode = 0: + break; + } + + return bFound; +} + + +// ------------------------------------------------------------------------- +// class ExtTextView +// ------------------------------------------------------------------------- +ExtTextView::ExtTextView( ExtTextEngine* pEng, Window* pWindow ) + : TextView( pEng, pWindow ) +{ +} + +ExtTextView::~ExtTextView() +{ +} + +sal_Bool ExtTextView::MatchGroup() +{ + TextSelection aTmpSel( GetSelection() ); + aTmpSel.Justify(); + if ( ( aTmpSel.GetStart().GetPara() != aTmpSel.GetEnd().GetPara() ) || + ( ( aTmpSel.GetEnd().GetIndex() - aTmpSel.GetStart().GetIndex() ) > 1 ) ) + { + return sal_False; + } + + TextSelection aMatchSel = ((ExtTextEngine*)GetTextEngine())->MatchGroup( aTmpSel.GetStart() ); + if ( aMatchSel.HasRange() ) + SetSelection( aMatchSel ); + + return aMatchSel.HasRange() ? sal_True : sal_False; +} + +sal_Bool ExtTextView::Search( const util::SearchOptions& rSearchOptions, sal_Bool bForward ) +{ + sal_Bool bFound = sal_False; + TextSelection aSel( GetSelection() ); + if ( ((ExtTextEngine*)GetTextEngine())->Search( aSel, rSearchOptions, bForward ) ) + { + bFound = sal_True; + // Erstmal den Anfang des Wortes als Selektion einstellen, + // damit das ganze Wort in den sichtbaren Bereich kommt. + SetSelection( aSel.GetStart() ); + ShowCursor( sal_True, sal_False ); + } + else + { + aSel = GetSelection().GetEnd(); + } + + SetSelection( aSel ); + ShowCursor(); + + return bFound; +} + +sal_uInt16 ExtTextView::Replace( const util::SearchOptions& rSearchOptions, sal_Bool bAll, sal_Bool bForward ) +{ + sal_uInt16 nFound = 0; + + if ( !bAll ) + { + if ( GetSelection().HasRange() ) + { + InsertText( rSearchOptions.replaceString ); + nFound = 1; + Search( rSearchOptions, bForward ); // gleich zum naechsten + } + else + { + if( Search( rSearchOptions, bForward ) ) + nFound = 1; + } + } + else + { + // Der Writer ersetzt alle, vom Anfang bis Ende... + + ExtTextEngine* pTextEngine = (ExtTextEngine*)GetTextEngine(); + + // HideSelection(); + TextSelection aSel; + + sal_Bool bSearchInSelection = (0 != (rSearchOptions.searchFlag & util::SearchFlags::REG_NOT_BEGINOFLINE) ); + if ( bSearchInSelection ) + { + aSel = GetSelection(); + aSel.Justify(); + } + + TextSelection aSearchSel( aSel ); + + sal_Bool bFound = pTextEngine->Search( aSel, rSearchOptions, sal_True ); + if ( bFound ) + pTextEngine->UndoActionStart(); + while ( bFound ) + { + nFound++; + + TextPaM aNewStart = pTextEngine->ImpInsertText( aSel, rSearchOptions.replaceString ); + aSel = aSearchSel; + aSel.GetStart() = aNewStart; + bFound = pTextEngine->Search( aSel, rSearchOptions, sal_True ); + } + if ( nFound ) + { + SetSelection( aSel.GetStart() ); + pTextEngine->FormatAndUpdate( this ); + pTextEngine->UndoActionEnd(); + } + } + return nFound; +} + +sal_Bool ExtTextView::ImpIndentBlock( sal_Bool bRight ) +{ + sal_Bool bDone = sal_False; + + TextSelection aSel = GetSelection(); + aSel.Justify(); + + HideSelection(); + GetTextEngine()->UndoActionStart(); + + sal_uLong nStartPara = aSel.GetStart().GetPara(); + sal_uLong nEndPara = aSel.GetEnd().GetPara(); + if ( aSel.HasRange() && !aSel.GetEnd().GetIndex() ) + { + nEndPara--; // den dann nicht einruecken... + } + + for ( sal_uLong nPara = nStartPara; nPara <= nEndPara; nPara++ ) + { + if ( bRight ) + { + // Tabs hinzufuegen + GetTextEngine()->ImpInsertText( TextPaM( nPara, 0 ), '\t' ); + bDone = sal_True; + } + else + { + // Tabs/Blanks entfernen + String aText = GetTextEngine()->GetText( nPara ); + if ( aText.Len() && ( + ( aText.GetChar( 0 ) == '\t' ) || + ( aText.GetChar( 0 ) == ' ' ) ) ) + { + GetTextEngine()->ImpDeleteText( TextSelection( TextPaM( nPara, 0 ), TextPaM( nPara, 1 ) ) ); + bDone = sal_True; + } + } + } + + GetTextEngine()->UndoActionEnd(); + + sal_Bool bRange = aSel.HasRange(); + if ( bRight ) + { + aSel.GetStart().GetIndex()++; + if ( bRange && ( aSel.GetEnd().GetPara() == nEndPara ) ) + aSel.GetEnd().GetIndex()++; + } + else + { + if ( aSel.GetStart().GetIndex() ) + aSel.GetStart().GetIndex()--; + if ( bRange && aSel.GetEnd().GetIndex() ) + aSel.GetEnd().GetIndex()--; + } + + ImpSetSelection( aSel ); + GetTextEngine()->FormatAndUpdate( this ); + + return bDone; +} + +sal_Bool ExtTextView::IndentBlock() +{ + return ImpIndentBlock( sal_True ); +} + +sal_Bool ExtTextView::UnindentBlock() +{ + return ImpIndentBlock( sal_False ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/window/msgbox.cxx b/vcl/source/window/msgbox.cxx index 7d49f3e..2c20bab 100644 --- a/vcl/source/window/msgbox.cxx +++ b/vcl/source/window/msgbox.cxx @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -66,7 +67,7 @@ static void ImplInitMsgBoxImageList() void MessBox::ImplInitMessBoxData() { - mpFixedText = NULL; + mpVCLMultiLineEdit = NULL; mpFixedImage = NULL; mbHelpBtn = sal_False; mpCheckBox = NULL; @@ -203,7 +204,7 @@ void MessBox::ImplLoadRes( const ResId& ) MessBox::~MessBox() { - delete mpFixedText; + delete mpVCLMultiLineEdit; delete mpFixedImage; delete mpCheckBox; } @@ -236,16 +237,16 @@ void MessBox::ImplPosControls() Point aTextPos( IMPL_DIALOG_OFFSET, IMPL_DIALOG_OFFSET+IMPL_MSGBOX_OFFSET_EXTRA_Y ); Size aImageSize; Size aPageSize; - Size aFixedSize; + Size aMEditSize; long nTitleWidth; long nButtonSize = ImplGetButtonSize(); long nMaxWidth = GetDesktopRectPixel().GetWidth()-8; long nMaxLineWidth; long nWidth; - WinBits nWinStyle = WB_LEFT | WB_WORDBREAK | WB_NOLABEL | WB_INFO; + WinBits nWinStyle = WB_LEFT | WB_WORDBREAK | WB_NOLABEL; sal_uInt16 nTextStyle = TEXT_DRAW_MULTILINE | TEXT_DRAW_TOP | TEXT_DRAW_LEFT; - delete mpFixedText; + delete mpVCLMultiLineEdit; if ( mpFixedImage ) { delete mpFixedImage; @@ -325,25 +326,27 @@ void MessBox::ImplPosControls() aFormatRect = GetTextRect( aRect, aMessText, nTextStyle, &aTextInfo ); } - // Style fuer FixedText ermitteln + // Style fuer VCLMultiLineEdit ermitteln + mpVCLMultiLineEdit = new VCLMultiLineEdit( this, nWinStyle ); + mpVCLMultiLineEdit->SetText( aMessText ); + aMEditSize = mpVCLMultiLineEdit->CalcMinimumSize(); + aPageSize.Width() = aImageSize.Width(); - aFixedSize.Width() = aTextInfo.GetMaxLineWidth()+1; - aFixedSize.Height() = aFormatRect.GetHeight(); - if ( aFixedSize.Height() < aImageSize.Height() ) + if ( aMEditSize.Height() < aImageSize.Height() ) { nWinStyle |= WB_VCENTER; aPageSize.Height() = aImageSize.Height(); - aFixedSize.Height() = aImageSize.Height(); + aMEditSize.Height() = aImageSize.Height(); } else { nWinStyle |= WB_TOP; - aPageSize.Height() = aFixedSize.Height(); + aPageSize.Height() = aMEditSize.Height(); } if ( aImageSize.Width() ) aPageSize.Width() += IMPL_SEP_MSGBOX_IMAGE; aPageSize.Width() += (IMPL_DIALOG_OFFSET*2)+(IMPL_MSGBOX_OFFSET_EXTRA_X*2); - aPageSize.Width() += aFixedSize.Width()+1; + aPageSize.Width() += aMEditSize.Width()+1; aPageSize.Height() += (IMPL_DIALOG_OFFSET*2)+(IMPL_MSGBOX_OFFSET_EXTRA_Y*2); if ( aPageSize.Width() < IMPL_MINSIZE_MSGBOX_WIDTH ) @@ -353,7 +356,7 @@ void MessBox::ImplPosControls() if ( maCheckBoxText.Len() ) { - Size aMinCheckboxSize ( aFixedSize ); + Size aMinCheckboxSize ( aMEditSize ); if ( aPageSize.Width() < IMPL_MINSIZE_MSGBOX_WIDTH+80 ) { aPageSize.Width() = IMPL_MINSIZE_MSGBOX_WIDTH+80; @@ -388,7 +391,7 @@ void MessBox::ImplPosControls() mpCheckBox->SetText( maCheckBoxText ); Point aPos( aTextPos ); - aPos.Y() += aFixedSize.Height() + (IMPL_DIALOG_OFFSET)+(IMPL_MSGBOX_OFFSET_EXTRA_Y*2); + aPos.Y() += aMEditSize.Height() + (IMPL_DIALOG_OFFSET)+(IMPL_MSGBOX_OFFSET_EXTRA_Y*2); // increase messagebox aPageSize.Height() += aSize.Height() + (IMPL_DIALOG_OFFSET*2)+(IMPL_MSGBOX_OFFSET_EXTRA_Y*2); @@ -397,12 +400,10 @@ void MessBox::ImplPosControls() mpCheckBox->Show(); } - mpFixedText = new FixedText( this, nWinStyle ); - if( mpFixedText->GetStyle() & WB_EXTRAOFFSET ) // TODO: use CalcMinimumSize() instead - aFixedSize.Width() += 2; - mpFixedText->SetPosSizePixel( aTextPos, aFixedSize ); - mpFixedText->SetText( aMessText ); - mpFixedText->Show(); + + mpVCLMultiLineEdit->SetPosSizePixel( aTextPos, aMEditSize ); + mpVCLMultiLineEdit->Show(); + mpVCLMultiLineEdit->SetPaintTransparent(sal_True); SetPageSizePixel( aPageSize ); } -- 1.7.7