975 lines
32 KiB
C++
975 lines
32 KiB
C++
/* -*- 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 .
|
|
*/
|
|
|
|
#include <sal/config.h>
|
|
|
|
#include <hintids.hxx>
|
|
#include <cmdid.h>
|
|
|
|
#include <com/sun/star/beans/XMultiPropertySet.hpp>
|
|
#include <com/sun/star/beans/XPropertiesChangeListener.hpp>
|
|
#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
|
|
#include <cppuhelper/implbase.hxx>
|
|
#include <officecfg/Office/Common.hxx>
|
|
#include <rtl/ustring.hxx>
|
|
#include <sal/log.hxx>
|
|
#include <vcl/commandevent.hxx>
|
|
#include <vcl/event.hxx>
|
|
#include <vcl/svapp.hxx>
|
|
#include <vcl/textview.hxx>
|
|
#include <vcl/ptrstyle.hxx>
|
|
#include <sfx2/dispatch.hxx>
|
|
#include <sfx2/viewfrm.hxx>
|
|
#include <svtools/htmltokn.h>
|
|
#include <vcl/txtattr.hxx>
|
|
#include <vcl/settings.hxx>
|
|
#include <svtools/colorcfg.hxx>
|
|
#include <editeng/flstitem.hxx>
|
|
#include <vcl/metric.hxx>
|
|
#include <svtools/ctrltool.hxx>
|
|
#include <svtools/scrolladaptor.hxx>
|
|
#include <tools/time.hxx>
|
|
#include <swmodule.hxx>
|
|
#include <docsh.hxx>
|
|
#include <srcview.hxx>
|
|
#include <helpids.h>
|
|
#include <vector>
|
|
|
|
namespace
|
|
{
|
|
|
|
struct TextPortion
|
|
{
|
|
sal_uInt16 nStart, nEnd;
|
|
svtools::ColorConfigEntry eType;
|
|
};
|
|
|
|
}
|
|
|
|
#define MAX_SYNTAX_HIGHLIGHT 20
|
|
#define MAX_HIGHLIGHTTIME 200
|
|
|
|
typedef std::vector<TextPortion> TextPortions;
|
|
|
|
static void lcl_Highlight(std::u16string_view aSource, TextPortions& aPortionList)
|
|
{
|
|
const sal_Unicode cOpenBracket = '<';
|
|
const sal_Unicode cCloseBracket= '>';
|
|
const sal_Unicode cSlash = '/';
|
|
const sal_Unicode cExclamation = '!';
|
|
const sal_Unicode cMinus = '-';
|
|
const sal_Unicode cSpace = ' ';
|
|
const sal_Unicode cTab = 0x09;
|
|
const sal_Unicode cLF = 0x0a;
|
|
const sal_Unicode cCR = 0x0d;
|
|
|
|
const sal_Int32 nStrLen = aSource.size();
|
|
sal_Int32 nInsert = 0; // number of inserted portions
|
|
sal_Int32 nActPos = 0; // position, where '<' was found
|
|
sal_Int32 nPortStart = SAL_MAX_INT32; // for the TextPortion
|
|
sal_Int32 nPortEnd = 0;
|
|
TextPortion aText;
|
|
while(nActPos < nStrLen)
|
|
{
|
|
if((nActPos < nStrLen - 2) && (aSource[nActPos] == cOpenBracket))
|
|
{
|
|
svtools::ColorConfigEntry eFoundType = svtools::HTMLUNKNOWN;
|
|
// insert 'empty' portion
|
|
if(nPortEnd < nActPos - 1 )
|
|
{
|
|
// don't move at the beginning
|
|
aText.nStart = nPortEnd;
|
|
if(nInsert)
|
|
aText.nStart += 1;
|
|
aText.nEnd = nActPos - 1;
|
|
aText.eType = svtools::HTMLUNKNOWN;
|
|
aPortionList.push_back( aText );
|
|
nInsert++;
|
|
}
|
|
sal_Unicode cFollowFirst = aSource[nActPos + 1];
|
|
sal_Unicode cFollowNext = aSource[nActPos + 2];
|
|
if(cExclamation == cFollowFirst)
|
|
{
|
|
// "<!" SGML or comment
|
|
if(cMinus == cFollowNext &&
|
|
nActPos < nStrLen - 3 && cMinus == aSource[nActPos + 3])
|
|
{
|
|
eFoundType = svtools::HTMLCOMMENT;
|
|
}
|
|
else
|
|
eFoundType = svtools::HTMLSGML;
|
|
nPortStart = nActPos;
|
|
nPortEnd = nActPos + 1;
|
|
}
|
|
else if(cSlash == cFollowFirst)
|
|
{
|
|
// "</" ignore slash
|
|
nPortStart = nActPos;
|
|
nActPos++;
|
|
}
|
|
if(svtools::HTMLUNKNOWN == eFoundType)
|
|
{
|
|
// now here a keyword could follow
|
|
sal_uInt16 nSrchPos = nActPos;
|
|
while(++nSrchPos < nStrLen - 1)
|
|
{
|
|
sal_Unicode cNext = aSource[nSrchPos];
|
|
if( cNext == cSpace ||
|
|
cNext == cTab ||
|
|
cNext == cLF ||
|
|
cNext == cCR)
|
|
break;
|
|
else if(cNext == cCloseBracket)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if(nSrchPos > nActPos + 1)
|
|
{
|
|
// some string was found
|
|
OUString sToken( aSource.substr(nActPos + 1, nSrchPos - nActPos - 1 ) );
|
|
sToken = sToken.toAsciiUpperCase();
|
|
HtmlTokenId nToken = ::GetHTMLToken(sToken);
|
|
if(nToken != HtmlTokenId::NONE)
|
|
{
|
|
eFoundType = svtools::HTMLKEYWORD;
|
|
nPortEnd = nSrchPos;
|
|
nPortStart = nActPos;
|
|
}
|
|
else
|
|
SAL_WARN("sw", "HTML token " << sToken << " not recognised!");
|
|
}
|
|
}
|
|
// now we still have to look for '>'
|
|
if(svtools::HTMLUNKNOWN != eFoundType)
|
|
{
|
|
bool bFound = false;
|
|
for(sal_Int32 i = nPortEnd; i < nStrLen; i++)
|
|
if(cCloseBracket == aSource[i])
|
|
{
|
|
bFound = true;
|
|
nPortEnd = i;
|
|
break;
|
|
}
|
|
if(!bFound && (eFoundType == svtools::HTMLCOMMENT))
|
|
{
|
|
// comment without ending in this line
|
|
bFound = true;
|
|
nPortEnd = nStrLen - 1;
|
|
}
|
|
|
|
if(bFound ||(eFoundType == svtools::HTMLCOMMENT))
|
|
{
|
|
TextPortion aTextPortion;
|
|
aTextPortion.nStart = nPortStart + 1;
|
|
aTextPortion.nEnd = nPortEnd;
|
|
aTextPortion.eType = eFoundType;
|
|
aPortionList.push_back( aTextPortion );
|
|
nInsert++;
|
|
}
|
|
|
|
}
|
|
}
|
|
nActPos++;
|
|
}
|
|
if(nInsert && nPortEnd < nActPos - 1)
|
|
{
|
|
aText.nStart = nPortEnd + 1;
|
|
aText.nEnd = nActPos - 1;
|
|
aText.eType = svtools::HTMLUNKNOWN;
|
|
aPortionList.push_back( aText );
|
|
nInsert++;
|
|
}
|
|
}
|
|
|
|
class SwSrcEditWindow::ChangesListener:
|
|
public cppu::WeakImplHelper< css::beans::XPropertiesChangeListener >
|
|
{
|
|
public:
|
|
explicit ChangesListener(SwSrcEditWindow & editor): m_Editor(editor) {}
|
|
|
|
private:
|
|
virtual ~ChangesListener() override {}
|
|
|
|
virtual void SAL_CALL disposing(css::lang::EventObject const &) override
|
|
{
|
|
std::unique_lock g(m_Editor.mutex_);
|
|
m_Editor.m_xNotifier.clear();
|
|
}
|
|
|
|
virtual void SAL_CALL propertiesChange(
|
|
css::uno::Sequence< css::beans::PropertyChangeEvent > const &) override
|
|
{
|
|
SolarMutexGuard g;
|
|
m_Editor.SetFont();
|
|
}
|
|
|
|
SwSrcEditWindow & m_Editor;
|
|
};
|
|
|
|
SwSrcEditWindow::SwSrcEditWindow( vcl::Window* pParent, SwSrcView* pParentView ) :
|
|
Window( pParent, WB_BORDER|WB_CLIPCHILDREN ),
|
|
|
|
m_pOutWin(nullptr),
|
|
m_pHScrollbar(nullptr),
|
|
m_pVScrollbar(nullptr),
|
|
|
|
m_pSrcView(pParentView),
|
|
|
|
m_nCurTextWidth(0),
|
|
m_nStartLine(USHRT_MAX),
|
|
m_eSourceEncoding(osl_getThreadTextEncoding()),
|
|
m_bReadonly(false),
|
|
m_bHighlighting(false),
|
|
m_aSyntaxIdle("sw uibase SwSrcEditWindow Syntax")
|
|
{
|
|
SetHelpId(HID_SOURCE_EDITWIN);
|
|
CreateTextEngine();
|
|
|
|
// Using "this" in ctor is a little fishy, but should work here at least as
|
|
// long as there are no derivations:
|
|
m_xListener = new ChangesListener(*this);
|
|
css::uno::Reference< css::beans::XMultiPropertySet > n(
|
|
officecfg::Office::Common::Font::SourceViewFont::get(),
|
|
css::uno::UNO_QUERY_THROW);
|
|
{
|
|
std::unique_lock g(mutex_);
|
|
m_xNotifier = n;
|
|
}
|
|
n->addPropertiesChangeListener({ u"FontHeight"_ustr, u"FontName"_ustr }, m_xListener);
|
|
}
|
|
|
|
SwSrcEditWindow::~SwSrcEditWindow()
|
|
{
|
|
disposeOnce();
|
|
}
|
|
|
|
void SwSrcEditWindow::dispose()
|
|
{
|
|
css::uno::Reference< css::beans::XMultiPropertySet > n;
|
|
{
|
|
std::unique_lock g(mutex_);
|
|
n = m_xNotifier;
|
|
}
|
|
if (n.is()) {
|
|
n->removePropertiesChangeListener(m_xListener);
|
|
}
|
|
m_aSyntaxIdle.Stop();
|
|
if ( m_pOutWin )
|
|
m_pOutWin->SetTextView( nullptr );
|
|
|
|
if ( m_pTextEngine )
|
|
{
|
|
EndListening( *m_pTextEngine );
|
|
m_pTextEngine->RemoveView( m_pTextView.get() );
|
|
|
|
m_pTextView.reset();
|
|
m_pTextEngine.reset();
|
|
}
|
|
m_pHScrollbar.disposeAndClear();
|
|
m_pVScrollbar.disposeAndClear();
|
|
m_pOutWin.disposeAndClear();
|
|
vcl::Window::dispose();
|
|
}
|
|
|
|
void SwSrcEditWindow::DataChanged( const DataChangedEvent& rDCEvt )
|
|
{
|
|
Window::DataChanged( rDCEvt );
|
|
|
|
switch ( rDCEvt.GetType() )
|
|
{
|
|
case DataChangedEventType::SETTINGS:
|
|
// newly rearrange ScrollBars or trigger Resize, because
|
|
// ScrollBar size could have changed. For this, in the
|
|
// Resize handler the size of ScrollBars has to be queried
|
|
// from the settings as well.
|
|
if( rDCEvt.GetFlags() & AllSettingsFlags::STYLE )
|
|
Resize();
|
|
break;
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
void SwSrcEditWindow::Resize()
|
|
{
|
|
// ScrollBars, etc. happens in Adjust...
|
|
if ( !m_pTextView )
|
|
return;
|
|
|
|
tools::Long nVisY = m_pTextView->GetStartDocPos().Y();
|
|
m_pTextView->ShowCursor();
|
|
Size aOutSz( GetOutputSizePixel() );
|
|
tools::Long nMaxVisAreaStart = m_pTextView->GetTextEngine()->GetTextHeight() - aOutSz.Height();
|
|
if ( nMaxVisAreaStart < 0 )
|
|
nMaxVisAreaStart = 0;
|
|
if ( m_pTextView->GetStartDocPos().Y() > nMaxVisAreaStart )
|
|
{
|
|
Point aStartDocPos( m_pTextView->GetStartDocPos() );
|
|
aStartDocPos.setY( nMaxVisAreaStart );
|
|
m_pTextView->SetStartDocPos( aStartDocPos );
|
|
m_pTextView->ShowCursor();
|
|
}
|
|
tools::Long nScrollStd = GetSettings().GetStyleSettings().GetScrollBarSize();
|
|
Size aScrollSz(aOutSz.Width() - nScrollStd, nScrollStd );
|
|
Point aScrollPos(0, aOutSz.Height() - nScrollStd);
|
|
|
|
m_pHScrollbar->SetPosSizePixel( aScrollPos, aScrollSz);
|
|
|
|
aScrollSz.setWidth( aScrollSz.Height() );
|
|
aScrollSz.setHeight( aOutSz.Height() );
|
|
aScrollPos = Point(aOutSz.Width() - nScrollStd, 0);
|
|
|
|
m_pVScrollbar->SetPosSizePixel( aScrollPos, aScrollSz);
|
|
aOutSz.AdjustWidth( -nScrollStd );
|
|
aOutSz.AdjustHeight( -nScrollStd );
|
|
m_pOutWin->SetOutputSizePixel(aOutSz);
|
|
InitScrollBars();
|
|
|
|
// set line in first Resize
|
|
if(USHRT_MAX != m_nStartLine)
|
|
{
|
|
if(m_nStartLine < m_pTextEngine->GetParagraphCount())
|
|
{
|
|
TextSelection aSel(TextPaM( m_nStartLine, 0 ), TextPaM( m_nStartLine, 0x0 ));
|
|
m_pTextView->SetSelection(aSel);
|
|
m_pTextView->ShowCursor();
|
|
}
|
|
m_nStartLine = USHRT_MAX;
|
|
}
|
|
|
|
if ( nVisY != m_pTextView->GetStartDocPos().Y() )
|
|
Invalidate();
|
|
|
|
|
|
}
|
|
|
|
void TextViewOutWin::DataChanged( const DataChangedEvent& rDCEvt )
|
|
{
|
|
Window::DataChanged( rDCEvt );
|
|
|
|
switch( rDCEvt.GetType() )
|
|
{
|
|
case DataChangedEventType::SETTINGS:
|
|
// query settings
|
|
if( rDCEvt.GetFlags() & AllSettingsFlags::STYLE )
|
|
{
|
|
const Color &rCol = GetSettings().GetStyleSettings().GetWindowColor();
|
|
SetBackground( rCol );
|
|
vcl::Font aFont( m_pTextView->GetTextEngine()->GetFont() );
|
|
aFont.SetFillColor( rCol );
|
|
m_pTextView->GetTextEngine()->SetFont( aFont );
|
|
}
|
|
break;
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
void TextViewOutWin::MouseMove( const MouseEvent &rEvt )
|
|
{
|
|
if ( m_pTextView )
|
|
m_pTextView->MouseMove( rEvt );
|
|
}
|
|
|
|
void TextViewOutWin::MouseButtonUp( const MouseEvent &rEvt )
|
|
{
|
|
if ( m_pTextView )
|
|
{
|
|
m_pTextView->MouseButtonUp( rEvt );
|
|
SfxViewFrame& rFrame = static_cast<SwSrcEditWindow*>(GetParent())->GetSrcView()->GetViewFrame();
|
|
SfxBindings& rBindings = rFrame.GetBindings();
|
|
rBindings.Invalidate( SID_TABLE_CELL );
|
|
rBindings.Invalidate( SID_CUT );
|
|
rBindings.Invalidate( SID_COPY );
|
|
}
|
|
}
|
|
|
|
void TextViewOutWin::MouseButtonDown( const MouseEvent &rEvt )
|
|
{
|
|
GrabFocus();
|
|
if ( m_pTextView )
|
|
m_pTextView->MouseButtonDown( rEvt );
|
|
}
|
|
|
|
void TextViewOutWin::Command( const CommandEvent& rCEvt )
|
|
{
|
|
switch(rCEvt.GetCommand())
|
|
{
|
|
case CommandEventId::ContextMenu:
|
|
SfxDispatcher::ExecutePopup();
|
|
break;
|
|
case CommandEventId::Wheel:
|
|
case CommandEventId::StartAutoScroll:
|
|
case CommandEventId::AutoScroll:
|
|
{
|
|
const CommandWheelData* pWData = rCEvt.GetWheelData();
|
|
if( !pWData || CommandWheelMode::ZOOM != pWData->GetMode() )
|
|
{
|
|
static_cast<SwSrcEditWindow*>(GetParent())->HandleWheelCommand( rCEvt );
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if ( m_pTextView )
|
|
m_pTextView->Command( rCEvt );
|
|
else
|
|
Window::Command(rCEvt);
|
|
}
|
|
}
|
|
|
|
void TextViewOutWin::KeyInput( const KeyEvent& rKEvt )
|
|
{
|
|
bool bDone = false;
|
|
SwSrcEditWindow* pSrcEditWin = static_cast<SwSrcEditWindow*>(GetParent());
|
|
bool bChange = !pSrcEditWin->IsReadonly() || !TextEngine::DoesKeyChangeText( rKEvt );
|
|
if(bChange)
|
|
bDone = m_pTextView->KeyInput( rKEvt );
|
|
|
|
SfxBindings& rBindings = static_cast<SwSrcEditWindow*>(GetParent())->GetSrcView()->GetViewFrame().GetBindings();
|
|
if ( !bDone )
|
|
{
|
|
if ( !SfxViewShell::Current()->KeyInput( rKEvt ) )
|
|
Window::KeyInput( rKEvt );
|
|
}
|
|
else
|
|
{
|
|
rBindings.Invalidate( SID_TABLE_CELL );
|
|
if ( rKEvt.GetKeyCode().GetGroup() == KEYGROUP_CURSOR )
|
|
rBindings.Update( SID_BASICIDE_STAT_POS );
|
|
if (pSrcEditWin->GetTextEngine()->IsModified() )
|
|
{
|
|
rBindings.Invalidate( SID_SAVEDOC );
|
|
rBindings.Invalidate( SID_DOC_MODIFIED );
|
|
}
|
|
if( rKEvt.GetKeyCode().GetCode() == KEY_INSERT )
|
|
rBindings.Invalidate( SID_ATTR_INSERT );
|
|
}
|
|
|
|
rBindings.Invalidate( SID_CUT );
|
|
rBindings.Invalidate( SID_COPY );
|
|
|
|
SwDocShell* pDocShell = pSrcEditWin->GetSrcView()->GetDocShell();
|
|
if(pSrcEditWin->GetTextEngine()->IsModified())
|
|
{
|
|
pDocShell->SetModified();
|
|
}
|
|
}
|
|
|
|
void TextViewOutWin::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
|
|
{
|
|
m_pTextView->Paint(rRenderContext, rRect);
|
|
}
|
|
|
|
void SwSrcEditWindow::CreateTextEngine()
|
|
{
|
|
// FIXME RenderContext
|
|
|
|
const Color &rCol = GetSettings().GetStyleSettings().GetWindowColor();
|
|
m_pOutWin = VclPtr<TextViewOutWin>::Create(this, 0);
|
|
m_pOutWin->SetBackground(Wallpaper(rCol));
|
|
m_pOutWin->SetPointer(PointerStyle::Text);
|
|
m_pOutWin->Show();
|
|
|
|
// create Scrollbars
|
|
m_pHScrollbar = VclPtr<ScrollAdaptor>::Create(this, true);
|
|
m_pHScrollbar->EnableRTL( false );
|
|
m_pHScrollbar->SetScrollHdl(LINK(this, SwSrcEditWindow, HorzScrollHdl));
|
|
m_pHScrollbar->Show();
|
|
|
|
m_pVScrollbar = VclPtr<ScrollAdaptor>::Create(this, false);
|
|
m_pVScrollbar->EnableRTL( false );
|
|
m_pVScrollbar->SetScrollHdl(LINK(this, SwSrcEditWindow, VertScrollHdl));
|
|
m_pVScrollbar->Show();
|
|
|
|
m_pTextEngine.reset(new ExtTextEngine);
|
|
m_pTextView.reset(new TextView( m_pTextEngine.get(), m_pOutWin ));
|
|
m_pTextView->SetAutoIndentMode(true);
|
|
m_pOutWin->SetTextView(m_pTextView.get());
|
|
|
|
m_pTextEngine->SetUpdateMode( false );
|
|
m_pTextEngine->InsertView( m_pTextView.get() );
|
|
|
|
vcl::Font aFont;
|
|
aFont.SetTransparent( false );
|
|
aFont.SetFillColor( rCol );
|
|
SetPointFont(*GetOutDev(), aFont);
|
|
aFont = GetFont();
|
|
aFont.SetFillColor( rCol );
|
|
m_pOutWin->SetFont( aFont );
|
|
m_pTextEngine->SetFont( aFont );
|
|
|
|
m_aSyntaxIdle.SetInvokeHandler( LINK( this, SwSrcEditWindow, SyntaxTimerHdl ) );
|
|
|
|
m_pTextEngine->EnableUndo( true );
|
|
m_pTextEngine->SetUpdateMode( true );
|
|
|
|
m_pTextView->ShowCursor();
|
|
InitScrollBars();
|
|
StartListening( *m_pTextEngine );
|
|
|
|
SfxBindings& rBind = GetSrcView()->GetViewFrame().GetBindings();
|
|
rBind.Invalidate( SID_TABLE_CELL );
|
|
}
|
|
|
|
void SwSrcEditWindow::SetScrollBarRanges()
|
|
{
|
|
// Extra method, not InitScrollBars, because also for TextEngine events.
|
|
|
|
m_pHScrollbar->SetRange( Range( 0, m_nCurTextWidth-1 ) );
|
|
m_pVScrollbar->SetRange( Range(0, m_pTextEngine->GetTextHeight()-1) );
|
|
}
|
|
|
|
void SwSrcEditWindow::InitScrollBars()
|
|
{
|
|
SetScrollBarRanges();
|
|
|
|
Size aOutSz( m_pOutWin->GetOutputSizePixel() );
|
|
m_pVScrollbar->SetVisibleSize( aOutSz.Height() );
|
|
m_pVScrollbar->SetPageSize( aOutSz.Height() * 8 / 10 );
|
|
m_pVScrollbar->SetLineSize( m_pOutWin->GetTextHeight() );
|
|
m_pVScrollbar->SetThumbPos( m_pTextView->GetStartDocPos().Y() );
|
|
m_pHScrollbar->SetVisibleSize( aOutSz.Width() );
|
|
m_pHScrollbar->SetPageSize( aOutSz.Width() * 8 / 10 );
|
|
m_pHScrollbar->SetLineSize( m_pOutWin->GetTextWidth(OUString('x')) );
|
|
m_pHScrollbar->SetThumbPos( m_pTextView->GetStartDocPos().X() );
|
|
|
|
}
|
|
|
|
IMPL_LINK_NOARG(SwSrcEditWindow, HorzScrollHdl, weld::Scrollbar&, void)
|
|
{
|
|
tools::Long nDiff = m_pTextView->GetStartDocPos().X() - m_pHScrollbar->GetThumbPos();
|
|
GetTextView()->Scroll( nDiff, 0 );
|
|
m_pTextView->ShowCursor( false );
|
|
m_pHScrollbar->SetThumbPos( m_pTextView->GetStartDocPos().X() );
|
|
GetSrcView()->GetViewFrame().GetBindings().Invalidate( SID_TABLE_CELL );
|
|
}
|
|
|
|
IMPL_LINK_NOARG(SwSrcEditWindow, VertScrollHdl, weld::Scrollbar&, void)
|
|
{
|
|
tools::Long nDiff = m_pTextView->GetStartDocPos().Y() - m_pVScrollbar->GetThumbPos();
|
|
GetTextView()->Scroll( 0, nDiff );
|
|
m_pTextView->ShowCursor( false );
|
|
m_pVScrollbar->SetThumbPos( m_pTextView->GetStartDocPos().Y() );
|
|
GetSrcView()->GetViewFrame().GetBindings().Invalidate( SID_TABLE_CELL );
|
|
}
|
|
|
|
IMPL_LINK( SwSrcEditWindow, SyntaxTimerHdl, Timer*, pIdle, void )
|
|
{
|
|
tools::Time aSyntaxCheckStart( tools::Time::SYSTEM );
|
|
SAL_WARN_IF(m_pTextView == nullptr, "sw", "No View yet, but syntax highlighting?!");
|
|
|
|
m_bHighlighting = true;
|
|
sal_uInt16 nCount = 0;
|
|
// at first the region around the cursor is processed
|
|
TextSelection aSel = m_pTextView->GetSelection();
|
|
sal_uInt16 nCur = o3tl::narrowing<sal_uInt16>(aSel.GetStart().GetPara());
|
|
if(nCur > 40)
|
|
nCur -= 40;
|
|
else
|
|
nCur = 0;
|
|
if(!m_aSyntaxLineTable.empty())
|
|
for(sal_uInt16 i = 0; i < 80 && nCount < 40; i++, nCur++)
|
|
{
|
|
if(m_aSyntaxLineTable.find(nCur) != m_aSyntaxLineTable.end())
|
|
{
|
|
DoSyntaxHighlight( nCur );
|
|
m_aSyntaxLineTable.erase( nCur );
|
|
nCount++;
|
|
if(m_aSyntaxLineTable.empty())
|
|
break;
|
|
if((tools::Time( tools::Time::SYSTEM ).GetTime() - aSyntaxCheckStart.GetTime()) > MAX_HIGHLIGHTTIME )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// when there is still anything left by then, go on from the beginning
|
|
while ( !m_aSyntaxLineTable.empty() && nCount < MAX_SYNTAX_HIGHLIGHT)
|
|
{
|
|
sal_uInt16 nLine = *m_aSyntaxLineTable.begin();
|
|
DoSyntaxHighlight( nLine );
|
|
m_aSyntaxLineTable.erase(nLine);
|
|
nCount ++;
|
|
if(tools::Time( tools::Time::SYSTEM ).GetTime() - aSyntaxCheckStart.GetTime() > MAX_HIGHLIGHTTIME)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!m_aSyntaxLineTable.empty() && !pIdle->IsActive())
|
|
pIdle->Start();
|
|
// SyntaxTimerHdl is called when text changed
|
|
// => good opportunity to determine text width!
|
|
tools::Long nPrevTextWidth = m_nCurTextWidth;
|
|
m_nCurTextWidth = m_pTextEngine->CalcTextWidth() + 25; // small tolerance
|
|
if ( m_nCurTextWidth != nPrevTextWidth )
|
|
SetScrollBarRanges();
|
|
m_bHighlighting = false;
|
|
}
|
|
|
|
void SwSrcEditWindow::DoSyntaxHighlight( sal_uInt16 nPara )
|
|
{
|
|
// Because of DelayedSyntaxHighlight it could happen,
|
|
// that the line doesn't exist anymore!
|
|
if ( nPara >= m_pTextEngine->GetParagraphCount() )
|
|
return;
|
|
|
|
bool bTempModified = IsModified();
|
|
m_pTextEngine->RemoveAttribs( nPara );
|
|
OUString aSource( m_pTextEngine->GetText( nPara ) );
|
|
m_pTextEngine->SetUpdateMode( false );
|
|
ImpDoHighlight( aSource, nPara );
|
|
TextView* pTmp = m_pTextEngine->GetActiveView();
|
|
pTmp->SetAutoScroll(false);
|
|
m_pTextEngine->SetActiveView(nullptr);
|
|
m_pTextEngine->SetUpdateMode( true );
|
|
m_pTextEngine->SetActiveView(pTmp);
|
|
pTmp->SetAutoScroll(true);
|
|
pTmp->ShowCursor( false/*pTmp->IsAutoScroll()*/ );
|
|
|
|
if(!bTempModified)
|
|
ClearModifyFlag();
|
|
|
|
}
|
|
|
|
void SwSrcEditWindow::ImpDoHighlight( std::u16string_view aSource, sal_uInt16 nLineOff )
|
|
{
|
|
TextPortions aPortionList;
|
|
lcl_Highlight(aSource, aPortionList);
|
|
|
|
size_t nCount = aPortionList.size();
|
|
if ( !nCount )
|
|
return;
|
|
|
|
TextPortion& rLast = aPortionList[nCount-1];
|
|
if ( rLast.nStart > rLast.nEnd ) // Only until Bug from MD is resolved
|
|
{
|
|
nCount--;
|
|
aPortionList.pop_back();
|
|
if ( !nCount )
|
|
return;
|
|
}
|
|
|
|
{
|
|
// Only blanks and tabs have to be attributed along.
|
|
// When two identical attributes are placed consecutively,
|
|
// it optimises the TextEngine.
|
|
sal_uInt16 nLastEnd = 0;
|
|
|
|
for ( size_t i = 0; i < nCount; i++ )
|
|
{
|
|
TextPortion& r = aPortionList[i];
|
|
if ( r.nStart > r.nEnd ) // only until Bug from MD is resolved
|
|
continue;
|
|
|
|
if ( r.nStart > nLastEnd )
|
|
{
|
|
// Can I rely on the fact that all except blank and tab
|
|
// are being highlighted?!
|
|
r.nStart = nLastEnd;
|
|
}
|
|
nLastEnd = r.nEnd+1;
|
|
if ( ( i == (nCount-1) ) && ( r.nEnd < aSource.size() ) )
|
|
r.nEnd = aSource.size();
|
|
}
|
|
}
|
|
|
|
for (TextPortion & r : aPortionList)
|
|
{
|
|
if ( r.nStart > r.nEnd ) // only until Bug from MD is resolved
|
|
continue;
|
|
if(r.eType != svtools::HTMLSGML &&
|
|
r.eType != svtools::HTMLCOMMENT &&
|
|
r.eType != svtools::HTMLKEYWORD &&
|
|
r.eType != svtools::HTMLUNKNOWN)
|
|
r.eType = svtools::HTMLUNKNOWN;
|
|
Color aColor(SwModule::get()->GetColorConfig().GetColorValue(r.eType).nColor);
|
|
m_pTextEngine->SetAttrib( TextAttribFontColor( aColor ), nLineOff, r.nStart, r.nEnd+1 );
|
|
}
|
|
}
|
|
|
|
void SwSrcEditWindow::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
|
|
{
|
|
switch (rHint.GetId())
|
|
{
|
|
case SfxHintId::TextViewScrolled:
|
|
m_pHScrollbar->SetThumbPos( m_pTextView->GetStartDocPos().X() );
|
|
m_pVScrollbar->SetThumbPos( m_pTextView->GetStartDocPos().Y() );
|
|
break;
|
|
|
|
case SfxHintId::TextHeightChanged:
|
|
if ( m_pTextEngine->GetTextHeight() < m_pOutWin->GetOutputSizePixel().Height() )
|
|
m_pTextView->Scroll( 0, m_pTextView->GetStartDocPos().Y() );
|
|
m_pVScrollbar->SetThumbPos( m_pTextView->GetStartDocPos().Y() );
|
|
SetScrollBarRanges();
|
|
break;
|
|
|
|
case SfxHintId::TextParaInserted:
|
|
case SfxHintId::TextParaContentChanged:
|
|
if ( !m_bHighlighting )
|
|
{
|
|
auto pTextHint = static_cast<const TextHint*>(&rHint);
|
|
m_aSyntaxLineTable.insert( o3tl::narrowing<sal_uInt16>(pTextHint->GetValue()) );
|
|
m_aSyntaxIdle.Start();
|
|
}
|
|
break;
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
void SwSrcEditWindow::ImplInvalidate(const vcl::Region* pRegion, InvalidateFlags nFlags)
|
|
{
|
|
m_pOutWin->Invalidate();
|
|
Window::ImplInvalidate(pRegion, nFlags);
|
|
}
|
|
|
|
void SwSrcEditWindow::Command( const CommandEvent& rCEvt )
|
|
{
|
|
switch(rCEvt.GetCommand())
|
|
{
|
|
case CommandEventId::Wheel:
|
|
case CommandEventId::StartAutoScroll:
|
|
case CommandEventId::AutoScroll:
|
|
{
|
|
const CommandWheelData* pWData = rCEvt.GetWheelData();
|
|
if( !pWData || CommandWheelMode::ZOOM != pWData->GetMode() )
|
|
HandleScrollCommand( rCEvt, m_pHScrollbar, m_pVScrollbar );
|
|
}
|
|
break;
|
|
default:
|
|
Window::Command(rCEvt);
|
|
}
|
|
}
|
|
|
|
void SwSrcEditWindow::HandleWheelCommand( const CommandEvent& rCEvt )
|
|
{
|
|
m_pTextView->Command(rCEvt);
|
|
HandleScrollCommand( rCEvt, m_pHScrollbar, m_pVScrollbar );
|
|
}
|
|
|
|
void SwSrcEditWindow::GetFocus()
|
|
{
|
|
if (m_pOutWin)
|
|
m_pOutWin->GrabFocus();
|
|
}
|
|
|
|
static bool lcl_GetLanguagesForEncoding(rtl_TextEncoding eEnc, LanguageType aLanguages[])
|
|
{
|
|
switch(eEnc)
|
|
{
|
|
case RTL_TEXTENCODING_UTF7 :
|
|
case RTL_TEXTENCODING_UTF8 :
|
|
// don#t fill - all LANGUAGE_SYSTEM means unicode font has to be used
|
|
break;
|
|
|
|
case RTL_TEXTENCODING_ISO_8859_3:
|
|
case RTL_TEXTENCODING_ISO_8859_1 :
|
|
case RTL_TEXTENCODING_MS_1252 :
|
|
case RTL_TEXTENCODING_APPLE_ROMAN :
|
|
case RTL_TEXTENCODING_IBM_850 :
|
|
case RTL_TEXTENCODING_ISO_8859_14 :
|
|
case RTL_TEXTENCODING_ISO_8859_15 :
|
|
//fill with western languages
|
|
aLanguages[0] = LANGUAGE_GERMAN;
|
|
aLanguages[1] = LANGUAGE_FRENCH;
|
|
aLanguages[2] = LANGUAGE_ITALIAN;
|
|
aLanguages[3] = LANGUAGE_SPANISH;
|
|
break;
|
|
|
|
case RTL_TEXTENCODING_IBM_865 :
|
|
//scandinavian
|
|
aLanguages[0] = LANGUAGE_FINNISH;
|
|
aLanguages[1] = LANGUAGE_NORWEGIAN;
|
|
aLanguages[2] = LANGUAGE_SWEDISH;
|
|
aLanguages[3] = LANGUAGE_DANISH;
|
|
break;
|
|
|
|
case RTL_TEXTENCODING_ISO_8859_10 :
|
|
case RTL_TEXTENCODING_ISO_8859_13 :
|
|
case RTL_TEXTENCODING_ISO_8859_2 :
|
|
case RTL_TEXTENCODING_IBM_852 :
|
|
case RTL_TEXTENCODING_MS_1250 :
|
|
case RTL_TEXTENCODING_APPLE_CENTEURO :
|
|
aLanguages[0] = LANGUAGE_POLISH;
|
|
aLanguages[1] = LANGUAGE_CZECH;
|
|
aLanguages[2] = LANGUAGE_HUNGARIAN;
|
|
aLanguages[3] = LANGUAGE_SLOVAK;
|
|
break;
|
|
|
|
case RTL_TEXTENCODING_ISO_8859_4 :
|
|
case RTL_TEXTENCODING_IBM_775 :
|
|
case RTL_TEXTENCODING_MS_1257 :
|
|
aLanguages[0] = LANGUAGE_LATVIAN ;
|
|
aLanguages[1] = LANGUAGE_LITHUANIAN;
|
|
aLanguages[2] = LANGUAGE_ESTONIAN ;
|
|
break;
|
|
|
|
case RTL_TEXTENCODING_IBM_863 : aLanguages[0] = LANGUAGE_FRENCH_CANADIAN; break;
|
|
case RTL_TEXTENCODING_APPLE_FARSI : aLanguages[0] = LANGUAGE_FARSI; break;
|
|
case RTL_TEXTENCODING_APPLE_ROMANIAN:aLanguages[0] = LANGUAGE_ROMANIAN; break;
|
|
|
|
case RTL_TEXTENCODING_IBM_861 :
|
|
case RTL_TEXTENCODING_APPLE_ICELAND :
|
|
aLanguages[0] = LANGUAGE_ICELANDIC;
|
|
break;
|
|
|
|
case RTL_TEXTENCODING_APPLE_CROATIAN:aLanguages[0] = LANGUAGE_CROATIAN; break;
|
|
|
|
case RTL_TEXTENCODING_IBM_437 :
|
|
case RTL_TEXTENCODING_ASCII_US : aLanguages[0] = LANGUAGE_ENGLISH; break;
|
|
|
|
case RTL_TEXTENCODING_IBM_862 :
|
|
case RTL_TEXTENCODING_MS_1255 :
|
|
case RTL_TEXTENCODING_APPLE_HEBREW :
|
|
case RTL_TEXTENCODING_ISO_8859_8 :
|
|
aLanguages[0] = LANGUAGE_HEBREW;
|
|
break;
|
|
|
|
case RTL_TEXTENCODING_IBM_857 :
|
|
case RTL_TEXTENCODING_MS_1254 :
|
|
case RTL_TEXTENCODING_APPLE_TURKISH:
|
|
case RTL_TEXTENCODING_ISO_8859_9 :
|
|
aLanguages[0] = LANGUAGE_TURKISH;
|
|
break;
|
|
|
|
case RTL_TEXTENCODING_IBM_860 :
|
|
aLanguages[0] = LANGUAGE_PORTUGUESE;
|
|
break;
|
|
|
|
case RTL_TEXTENCODING_IBM_869 :
|
|
case RTL_TEXTENCODING_MS_1253 :
|
|
case RTL_TEXTENCODING_APPLE_GREEK :
|
|
case RTL_TEXTENCODING_ISO_8859_7 :
|
|
case RTL_TEXTENCODING_IBM_737 :
|
|
aLanguages[0] = LANGUAGE_GREEK;
|
|
break;
|
|
|
|
case RTL_TEXTENCODING_KOI8_R :
|
|
case RTL_TEXTENCODING_ISO_8859_5 :
|
|
case RTL_TEXTENCODING_IBM_855 :
|
|
case RTL_TEXTENCODING_MS_1251 :
|
|
case RTL_TEXTENCODING_IBM_866 :
|
|
case RTL_TEXTENCODING_APPLE_CYRILLIC :
|
|
aLanguages[0] = LANGUAGE_RUSSIAN;
|
|
break;
|
|
|
|
case RTL_TEXTENCODING_APPLE_UKRAINIAN:
|
|
case RTL_TEXTENCODING_KOI8_U:
|
|
aLanguages[0] = LANGUAGE_UKRAINIAN;
|
|
break;
|
|
|
|
case RTL_TEXTENCODING_IBM_864 :
|
|
case RTL_TEXTENCODING_MS_1256 :
|
|
case RTL_TEXTENCODING_ISO_8859_6 :
|
|
case RTL_TEXTENCODING_APPLE_ARABIC :
|
|
aLanguages[0] = LANGUAGE_ARABIC_SAUDI_ARABIA;
|
|
break;
|
|
|
|
case RTL_TEXTENCODING_APPLE_CHINTRAD :
|
|
case RTL_TEXTENCODING_MS_950 :
|
|
case RTL_TEXTENCODING_GBT_12345 :
|
|
case RTL_TEXTENCODING_BIG5 :
|
|
case RTL_TEXTENCODING_EUC_TW :
|
|
case RTL_TEXTENCODING_BIG5_HKSCS :
|
|
aLanguages[0] = LANGUAGE_CHINESE_TRADITIONAL;
|
|
break;
|
|
|
|
case RTL_TEXTENCODING_EUC_JP :
|
|
case RTL_TEXTENCODING_ISO_2022_JP :
|
|
case RTL_TEXTENCODING_JIS_X_0201 :
|
|
case RTL_TEXTENCODING_JIS_X_0208 :
|
|
case RTL_TEXTENCODING_JIS_X_0212 :
|
|
case RTL_TEXTENCODING_APPLE_JAPANESE :
|
|
case RTL_TEXTENCODING_MS_932 :
|
|
case RTL_TEXTENCODING_SHIFT_JIS :
|
|
aLanguages[0] = LANGUAGE_JAPANESE;
|
|
break;
|
|
|
|
case RTL_TEXTENCODING_GB_2312 :
|
|
case RTL_TEXTENCODING_MS_936 :
|
|
case RTL_TEXTENCODING_GBK :
|
|
case RTL_TEXTENCODING_GB_18030 :
|
|
case RTL_TEXTENCODING_APPLE_CHINSIMP :
|
|
case RTL_TEXTENCODING_EUC_CN :
|
|
case RTL_TEXTENCODING_ISO_2022_CN :
|
|
aLanguages[0] = LANGUAGE_CHINESE_SIMPLIFIED;
|
|
break;
|
|
|
|
case RTL_TEXTENCODING_APPLE_KOREAN :
|
|
case RTL_TEXTENCODING_MS_949 :
|
|
case RTL_TEXTENCODING_EUC_KR :
|
|
case RTL_TEXTENCODING_ISO_2022_KR :
|
|
case RTL_TEXTENCODING_MS_1361 :
|
|
aLanguages[0] = LANGUAGE_KOREAN;
|
|
break;
|
|
|
|
case RTL_TEXTENCODING_APPLE_THAI :
|
|
case RTL_TEXTENCODING_MS_874 :
|
|
case RTL_TEXTENCODING_TIS_620 :
|
|
aLanguages[0] = LANGUAGE_THAI;
|
|
break;
|
|
default: aLanguages[0] = Application::GetSettings().GetUILanguageTag().getLanguageType();
|
|
}
|
|
return aLanguages[0] != LANGUAGE_SYSTEM;
|
|
}
|
|
void SwSrcEditWindow::SetFont()
|
|
{
|
|
OUString sFontName(
|
|
officecfg::Office::Common::Font::SourceViewFont::FontName::get().
|
|
value_or(OUString()));
|
|
if(sFontName.isEmpty())
|
|
{
|
|
LanguageType aLanguages[5] =
|
|
{
|
|
LANGUAGE_SYSTEM, LANGUAGE_SYSTEM, LANGUAGE_SYSTEM, LANGUAGE_SYSTEM, LANGUAGE_SYSTEM
|
|
};
|
|
vcl::Font aFont;
|
|
if(lcl_GetLanguagesForEncoding(m_eSourceEncoding, aLanguages))
|
|
{
|
|
//TODO: check for multiple languages
|
|
aFont = OutputDevice::GetDefaultFont(DefaultFontType::FIXED, aLanguages[0], GetDefaultFontFlags::NONE, GetOutDev());
|
|
}
|
|
else
|
|
aFont = OutputDevice::GetDefaultFont(DefaultFontType::SANS_UNICODE,
|
|
Application::GetSettings().GetLanguageTag().getLanguageType(), GetDefaultFontFlags::NONE, GetOutDev());
|
|
sFontName = aFont.GetFamilyName();
|
|
}
|
|
const SvxFontListItem* pFontListItem =
|
|
static_cast<const SvxFontListItem* >(m_pSrcView->GetDocShell()->GetItem( SID_ATTR_CHAR_FONTLIST ));
|
|
const FontList* pList = pFontListItem->GetFontList();
|
|
vcl::Font aFont(pList->Get(sFontName, WEIGHT_NORMAL, ITALIC_NONE));
|
|
|
|
const vcl::Font& rFont = GetTextEngine()->GetFont();
|
|
Size aSize(rFont.GetFontSize());
|
|
//font height is stored in point and set in twip
|
|
aSize.setHeight(
|
|
officecfg::Office::Common::Font::SourceViewFont::FontHeight::get() * 20 );
|
|
aFont.SetFontSize(m_pOutWin->LogicToPixel(aSize, MapMode(MapUnit::MapTwip)));
|
|
GetTextEngine()->SetFont( aFont );
|
|
m_pOutWin->SetFont(aFont);
|
|
}
|
|
|
|
void SwSrcEditWindow::SetTextEncoding(rtl_TextEncoding eEncoding)
|
|
{
|
|
m_eSourceEncoding = eEncoding;
|
|
SetFont();
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|