Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <sal/config.h>
21 :
22 : #include <hintids.hxx>
23 : #include <cmdid.h>
24 :
25 : #include <com/sun/star/beans/XMultiPropertySet.hpp>
26 : #include <com/sun/star/beans/XPropertiesChangeListener.hpp>
27 : #include <cppuhelper/implbase.hxx>
28 : #include <officecfg/Office/Common.hxx>
29 : #include <rtl/ustring.hxx>
30 : #include <sal/log.hxx>
31 : #include <vcl/textview.hxx>
32 : #include <svx/svxids.hrc>
33 : #include <vcl/scrbar.hxx>
34 : #include <sfx2/dispatch.hxx>
35 : #include <sfx2/app.hxx>
36 : #include <svtools/htmltokn.h>
37 : #include <vcl/txtattr.hxx>
38 : #include <vcl/settings.hxx>
39 : #include <svtools/colorcfg.hxx>
40 : #include <editeng/flstitem.hxx>
41 : #include <vcl/metric.hxx>
42 : #include <svtools/ctrltool.hxx>
43 : #include <tools/time.hxx>
44 : #include <swmodule.hxx>
45 : #include <docsh.hxx>
46 : #include <srcview.hxx>
47 : #include <helpid.h>
48 : #include <deque>
49 :
50 : struct SwTextPortion
51 : {
52 : sal_uInt16 nLine;
53 : sal_uInt16 nStart, nEnd;
54 : svtools::ColorConfigEntry eType;
55 : };
56 :
57 : #define MAX_SYNTAX_HIGHLIGHT 20
58 : #define MAX_HIGHLIGHTTIME 200
59 :
60 : typedef std::deque<SwTextPortion> SwTextPortions;
61 :
62 0 : static void lcl_Highlight(const OUString& rSource, SwTextPortions& aPortionList)
63 : {
64 0 : const sal_Unicode cOpenBracket = '<';
65 0 : const sal_Unicode cCloseBracket= '>';
66 0 : const sal_Unicode cSlash = '/';
67 0 : const sal_Unicode cExclamation = '!';
68 0 : const sal_Unicode cMinus = '-';
69 0 : const sal_Unicode cSpace = ' ';
70 0 : const sal_Unicode cTab = 0x09;
71 0 : const sal_Unicode cLF = 0x0a;
72 0 : const sal_Unicode cCR = 0x0d;
73 :
74 0 : const sal_uInt16 nStrLen = rSource.getLength();
75 0 : sal_uInt16 nInsert = 0; // number of inserted portions
76 0 : sal_uInt16 nActPos = 0; // position, where '<' was found
77 0 : sal_uInt16 nOffset = 0; // Offset of nActPos to '<'
78 0 : sal_uInt16 nPortStart = USHRT_MAX; // for the TextPortion
79 0 : sal_uInt16 nPortEnd = 0;
80 : SwTextPortion aText;
81 0 : while(nActPos < nStrLen)
82 : {
83 0 : svtools::ColorConfigEntry eFoundType = svtools::HTMLUNKNOWN;
84 0 : if((nActPos < nStrLen - 2) && (rSource[nActPos] == cOpenBracket))
85 : {
86 : // insert 'empty' portion
87 0 : if(nPortEnd < nActPos - 1 )
88 : {
89 0 : aText.nLine = 0;
90 : // don't move at the beginning
91 0 : aText.nStart = nPortEnd;
92 0 : if(nInsert)
93 0 : aText.nStart += 1;
94 0 : aText.nEnd = nActPos - 1;
95 0 : aText.eType = svtools::HTMLUNKNOWN;
96 0 : aPortionList.push_back( aText );
97 0 : nInsert++;
98 : }
99 0 : sal_Unicode cFollowFirst = rSource[nActPos + 1];
100 0 : sal_Unicode cFollowNext = rSource[nActPos + 2];
101 0 : if(cExclamation == cFollowFirst)
102 : {
103 : // "<!" SGML or comment
104 0 : if(cMinus == cFollowNext &&
105 0 : nActPos < nStrLen - 3 && cMinus == rSource[nActPos + 3])
106 : {
107 0 : eFoundType = svtools::HTMLCOMMENT;
108 : }
109 : else
110 0 : eFoundType = svtools::HTMLSGML;
111 0 : nPortStart = nActPos;
112 0 : nPortEnd = nActPos + 1;
113 : }
114 0 : else if(cSlash == cFollowFirst)
115 : {
116 : // "</" ignore slash
117 0 : nPortStart = nActPos;
118 0 : nActPos++;
119 0 : nOffset++;
120 : }
121 0 : if(svtools::HTMLUNKNOWN == eFoundType)
122 : {
123 : // now here a keyword could follow
124 0 : sal_uInt16 nSrchPos = nActPos;
125 0 : while(++nSrchPos < nStrLen - 1)
126 : {
127 0 : sal_Unicode cNext = rSource[nSrchPos];
128 0 : if( cNext == cSpace ||
129 0 : cNext == cTab ||
130 0 : cNext == cLF ||
131 : cNext == cCR)
132 : break;
133 0 : else if(cNext == cCloseBracket)
134 : {
135 0 : break;
136 : }
137 : }
138 0 : if(nSrchPos > nActPos + 1)
139 : {
140 : // some string was found
141 0 : OUString sToken = rSource.copy(nActPos + 1, nSrchPos - nActPos - 1 );
142 0 : sToken = sToken.toAsciiUpperCase();
143 0 : int nToken = ::GetHTMLToken(sToken);
144 0 : if(nToken)
145 : {
146 : // Token was found
147 0 : eFoundType = svtools::HTMLKEYWORD;
148 0 : nPortEnd = nSrchPos;
149 0 : nPortStart = nActPos;
150 : }
151 : else
152 : {
153 : // what was that?
154 : SAL_WARN(
155 : "sw.level2",
156 : "Token " << sToken
157 : << " not recognised!");
158 0 : }
159 :
160 : }
161 : }
162 : // now we still have to look for '>'
163 0 : if(svtools::HTMLUNKNOWN != eFoundType)
164 : {
165 0 : bool bFound = false;
166 0 : for(sal_uInt16 i = nPortEnd; i < nStrLen; i++)
167 0 : if(cCloseBracket == rSource[i])
168 : {
169 0 : bFound = true;
170 0 : nPortEnd = i;
171 0 : break;
172 : }
173 0 : if(!bFound && (eFoundType == svtools::HTMLCOMMENT))
174 : {
175 : // comment without ending in this line
176 0 : bFound = true;
177 0 : nPortEnd = nStrLen - 1;
178 : }
179 :
180 0 : if(bFound ||(eFoundType == svtools::HTMLCOMMENT))
181 : {
182 : SwTextPortion aTextPortion;
183 0 : aTextPortion.nLine = 0;
184 0 : aTextPortion.nStart = nPortStart + 1;
185 0 : aTextPortion.nEnd = nPortEnd;
186 0 : aTextPortion.eType = eFoundType;
187 0 : aPortionList.push_back( aTextPortion );
188 0 : nInsert++;
189 0 : eFoundType = svtools::HTMLUNKNOWN;
190 : }
191 :
192 : }
193 : }
194 0 : nActPos++;
195 : }
196 0 : if(nInsert && nPortEnd < nActPos - 1)
197 : {
198 0 : aText.nLine = 0;
199 0 : aText.nStart = nPortEnd + 1;
200 0 : aText.nEnd = nActPos - 1;
201 0 : aText.eType = svtools::HTMLUNKNOWN;
202 0 : aPortionList.push_back( aText );
203 0 : nInsert++;
204 : }
205 0 : }
206 :
207 : class SwSrcEditWindow::ChangesListener:
208 : public cppu::WeakImplHelper< css::beans::XPropertiesChangeListener >
209 : {
210 : public:
211 0 : explicit ChangesListener(SwSrcEditWindow & editor): editor_(editor) {}
212 :
213 : private:
214 0 : virtual ~ChangesListener() {}
215 :
216 0 : virtual void SAL_CALL disposing(css::lang::EventObject const &)
217 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
218 : {
219 0 : osl::MutexGuard g(editor_.mutex_);
220 0 : editor_.notifier_.clear();
221 0 : }
222 :
223 0 : virtual void SAL_CALL propertiesChange(
224 : css::uno::Sequence< css::beans::PropertyChangeEvent > const &)
225 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
226 : {
227 0 : SolarMutexGuard g;
228 0 : editor_.SetFont();
229 0 : }
230 :
231 : SwSrcEditWindow & editor_;
232 : };
233 :
234 0 : SwSrcEditWindow::SwSrcEditWindow( vcl::Window* pParent, SwSrcView* pParentView ) :
235 : Window( pParent, WB_BORDER|WB_CLIPCHILDREN ),
236 :
237 : pTextEngine(0),
238 :
239 : pOutWin(0),
240 : pHScrollbar(0),
241 : pVScrollbar(0),
242 :
243 : pSrcView(pParentView),
244 :
245 : nCurTextWidth(0),
246 : nStartLine(USHRT_MAX),
247 0 : eSourceEncoding(osl_getThreadTextEncoding()),
248 : bDoSyntaxHighlight(true),
249 0 : bHighlighting(false)
250 : {
251 0 : SetHelpId(HID_SOURCE_EDITWIN);
252 0 : CreateTextEngine();
253 :
254 : // Using "this" in ctor is a little fishy, but should work here at least as
255 : // long as there are no derivations:
256 0 : listener_ = new ChangesListener(*this);
257 : css::uno::Reference< css::beans::XMultiPropertySet > n(
258 : officecfg::Office::Common::Font::SourceViewFont::get(),
259 0 : css::uno::UNO_QUERY_THROW);
260 : {
261 0 : osl::MutexGuard g(mutex_);
262 0 : notifier_ = n;
263 : }
264 0 : css::uno::Sequence< OUString > s(2);
265 0 : s[0] = "FontHeight";
266 0 : s[1] = "FontName";
267 0 : n->addPropertiesChangeListener(s, listener_.get());
268 0 : }
269 :
270 0 : SwSrcEditWindow::~SwSrcEditWindow()
271 : {
272 0 : disposeOnce();
273 0 : }
274 :
275 0 : void SwSrcEditWindow::dispose()
276 : {
277 0 : css::uno::Reference< css::beans::XMultiPropertySet > n;
278 : {
279 0 : osl::MutexGuard g(mutex_);
280 0 : n = notifier_;
281 : }
282 0 : if (n.is()) {
283 0 : n->removePropertiesChangeListener(listener_.get());
284 : }
285 0 : aSyntaxIdle.Stop();
286 0 : if ( pTextEngine )
287 : {
288 0 : EndListening( *pTextEngine );
289 0 : pTextEngine->RemoveView( pTextView );
290 :
291 0 : delete pTextView;
292 0 : delete pTextEngine;
293 : }
294 0 : pHScrollbar.disposeAndClear();
295 0 : pVScrollbar.disposeAndClear();
296 0 : pOutWin.disposeAndClear();
297 0 : vcl::Window::dispose();
298 0 : }
299 :
300 0 : void SwSrcEditWindow::DataChanged( const DataChangedEvent& rDCEvt )
301 : {
302 0 : Window::DataChanged( rDCEvt );
303 :
304 0 : switch ( rDCEvt.GetType() )
305 : {
306 : case DataChangedEventType::SETTINGS:
307 : // newly rearrange ScrollBars or trigger Resize, because
308 : // ScrollBar size could have changed. For this, in the
309 : // Resize handler the size of ScrollBars has to be queried
310 : // from the settings as well.
311 0 : if( rDCEvt.GetFlags() & AllSettingsFlags::STYLE )
312 0 : Resize();
313 0 : break;
314 0 : default: break;
315 : }
316 0 : }
317 :
318 0 : void SwSrcEditWindow::Resize()
319 : {
320 : // ScrollBars, etc. happens in Adjust...
321 0 : if ( pTextView )
322 : {
323 0 : long nVisY = pTextView->GetStartDocPos().Y();
324 0 : pTextView->ShowCursor();
325 0 : Size aOutSz( GetOutputSizePixel() );
326 0 : long nMaxVisAreaStart = pTextView->GetTextEngine()->GetTextHeight() - aOutSz.Height();
327 0 : if ( nMaxVisAreaStart < 0 )
328 0 : nMaxVisAreaStart = 0;
329 0 : if ( pTextView->GetStartDocPos().Y() > nMaxVisAreaStart )
330 : {
331 0 : Point aStartDocPos( pTextView->GetStartDocPos() );
332 0 : aStartDocPos.Y() = nMaxVisAreaStart;
333 0 : pTextView->SetStartDocPos( aStartDocPos );
334 0 : pTextView->ShowCursor();
335 : }
336 0 : long nScrollStd = GetSettings().GetStyleSettings().GetScrollBarSize();
337 0 : Size aScrollSz(aOutSz.Width() - nScrollStd, nScrollStd );
338 0 : Point aScrollPos(0, aOutSz.Height() - nScrollStd);
339 :
340 0 : pHScrollbar->SetPosSizePixel( aScrollPos, aScrollSz);
341 :
342 0 : aScrollSz.Width() = aScrollSz.Height();
343 0 : aScrollSz.Height() = aOutSz.Height();
344 0 : aScrollPos = Point(aOutSz.Width() - nScrollStd, 0);
345 :
346 0 : pVScrollbar->SetPosSizePixel( aScrollPos, aScrollSz);
347 0 : aOutSz.Width() -= nScrollStd;
348 0 : aOutSz.Height() -= nScrollStd;
349 0 : pOutWin->SetOutputSizePixel(aOutSz);
350 0 : InitScrollBars();
351 :
352 : // set line in first Resize
353 0 : if(USHRT_MAX != nStartLine)
354 : {
355 0 : if(nStartLine < pTextEngine->GetParagraphCount())
356 : {
357 0 : TextSelection aSel(TextPaM( nStartLine, 0 ), TextPaM( nStartLine, 0x0 ));
358 0 : pTextView->SetSelection(aSel);
359 0 : pTextView->ShowCursor();
360 : }
361 0 : nStartLine = USHRT_MAX;
362 : }
363 :
364 0 : if ( nVisY != pTextView->GetStartDocPos().Y() )
365 0 : Invalidate();
366 : }
367 :
368 0 : }
369 :
370 0 : void TextViewOutWin::DataChanged( const DataChangedEvent& rDCEvt )
371 : {
372 0 : Window::DataChanged( rDCEvt );
373 :
374 0 : switch( rDCEvt.GetType() )
375 : {
376 : case DataChangedEventType::SETTINGS:
377 : // query settings
378 0 : if( rDCEvt.GetFlags() & AllSettingsFlags::STYLE )
379 : {
380 0 : const Color &rCol = GetSettings().GetStyleSettings().GetWindowColor();
381 0 : SetBackground( rCol );
382 0 : vcl::Font aFont( pTextView->GetTextEngine()->GetFont() );
383 0 : aFont.SetFillColor( rCol );
384 0 : pTextView->GetTextEngine()->SetFont( aFont );
385 : }
386 0 : break;
387 0 : default: break;
388 : }
389 0 : }
390 :
391 0 : void TextViewOutWin::MouseMove( const MouseEvent &rEvt )
392 : {
393 0 : if ( pTextView )
394 0 : pTextView->MouseMove( rEvt );
395 0 : }
396 :
397 0 : void TextViewOutWin::MouseButtonUp( const MouseEvent &rEvt )
398 : {
399 0 : if ( pTextView )
400 : {
401 0 : pTextView->MouseButtonUp( rEvt );
402 0 : SfxBindings& rBindings = static_cast<SwSrcEditWindow*>(GetParent())->GetSrcView()->GetViewFrame()->GetBindings();
403 0 : rBindings.Invalidate( SID_TABLE_CELL );
404 0 : rBindings.Invalidate( SID_CUT );
405 0 : rBindings.Invalidate( SID_COPY );
406 : }
407 0 : }
408 :
409 0 : void TextViewOutWin::MouseButtonDown( const MouseEvent &rEvt )
410 : {
411 0 : GrabFocus();
412 0 : if ( pTextView )
413 0 : pTextView->MouseButtonDown( rEvt );
414 0 : }
415 :
416 0 : void TextViewOutWin::Command( const CommandEvent& rCEvt )
417 : {
418 0 : switch(rCEvt.GetCommand())
419 : {
420 : case CommandEventId::ContextMenu:
421 0 : SfxDispatcher::ExecutePopup();
422 0 : break;
423 : case CommandEventId::Wheel:
424 : case CommandEventId::StartAutoScroll:
425 : case CommandEventId::AutoScroll:
426 : {
427 0 : const CommandWheelData* pWData = rCEvt.GetWheelData();
428 0 : if( !pWData || CommandWheelMode::ZOOM != pWData->GetMode() )
429 : {
430 0 : static_cast<SwSrcEditWindow*>(GetParent())->HandleWheelCommand( rCEvt );
431 : }
432 : }
433 0 : break;
434 :
435 : default:
436 0 : if ( pTextView )
437 0 : pTextView->Command( rCEvt );
438 : else
439 0 : Window::Command(rCEvt);
440 : }
441 0 : }
442 :
443 0 : void TextViewOutWin::KeyInput( const KeyEvent& rKEvt )
444 : {
445 0 : bool bDone = false;
446 0 : SwSrcEditWindow* pSrcEditWin = static_cast<SwSrcEditWindow*>(GetParent());
447 0 : bool bChange = !pSrcEditWin->IsReadonly() || !TextEngine::DoesKeyChangeText( rKEvt );
448 0 : if(bChange)
449 0 : bDone = pTextView->KeyInput( rKEvt );
450 :
451 0 : SfxBindings& rBindings = static_cast<SwSrcEditWindow*>(GetParent())->GetSrcView()->GetViewFrame()->GetBindings();
452 0 : if ( !bDone )
453 : {
454 0 : if ( !SfxViewShell::Current()->KeyInput( rKEvt ) )
455 0 : Window::KeyInput( rKEvt );
456 : }
457 : else
458 : {
459 0 : rBindings.Invalidate( SID_TABLE_CELL );
460 0 : if ( rKEvt.GetKeyCode().GetGroup() == KEYGROUP_CURSOR )
461 0 : rBindings.Update( SID_BASICIDE_STAT_POS );
462 0 : if (pSrcEditWin->GetTextEngine()->IsModified() )
463 : {
464 0 : rBindings.Invalidate( SID_SAVEDOC );
465 0 : rBindings.Invalidate( SID_DOC_MODIFIED );
466 : }
467 0 : if( rKEvt.GetKeyCode().GetCode() == KEY_INSERT )
468 0 : rBindings.Invalidate( SID_ATTR_INSERT );
469 : }
470 :
471 0 : rBindings.Invalidate( SID_CUT );
472 0 : rBindings.Invalidate( SID_COPY );
473 :
474 0 : SwDocShell* pDocShell = pSrcEditWin->GetSrcView()->GetDocShell();
475 0 : if(pSrcEditWin->GetTextEngine()->IsModified())
476 : {
477 0 : pDocShell->SetModified();
478 : }
479 0 : }
480 :
481 0 : void TextViewOutWin::Paint(vcl::RenderContext& rRenderContext, const Rectangle& rRect)
482 : {
483 0 : pTextView->Paint(rRenderContext, rRect);
484 0 : }
485 :
486 0 : void SwSrcEditWindow::CreateTextEngine()
487 : {
488 : // FIXME RenderContext
489 :
490 0 : const Color &rCol = GetSettings().GetStyleSettings().GetWindowColor();
491 0 : pOutWin = VclPtr<TextViewOutWin>::Create(this, 0);
492 0 : pOutWin->SetBackground(Wallpaper(rCol));
493 0 : pOutWin->SetPointer(Pointer(PointerStyle::Text));
494 0 : pOutWin->Show();
495 :
496 : // create Scrollbars
497 0 : pHScrollbar = VclPtr<ScrollBar>::Create(this, WB_3DLOOK |WB_HSCROLL|WB_DRAG);
498 0 : pHScrollbar->EnableRTL( false ); // --- RTL --- no mirroring for scrollbars
499 0 : pHScrollbar->SetScrollHdl(LINK(this, SwSrcEditWindow, ScrollHdl));
500 0 : pHScrollbar->Show();
501 :
502 0 : pVScrollbar = VclPtr<ScrollBar>::Create(this, WB_3DLOOK |WB_VSCROLL|WB_DRAG);
503 0 : pVScrollbar->EnableRTL( false ); // --- RTL --- no mirroring for scrollbars
504 0 : pVScrollbar->SetScrollHdl(LINK(this, SwSrcEditWindow, ScrollHdl));
505 0 : pHScrollbar->EnableDrag();
506 0 : pVScrollbar->Show();
507 :
508 0 : pTextEngine = new ExtTextEngine;
509 0 : pTextView = new ExtTextView( pTextEngine, pOutWin );
510 0 : pTextView->SetAutoIndentMode(true);
511 0 : pOutWin->SetTextView(pTextView);
512 :
513 0 : pTextEngine->SetUpdateMode( false );
514 0 : pTextEngine->InsertView( pTextView );
515 :
516 0 : vcl::Font aFont;
517 0 : aFont.SetTransparent( false );
518 0 : aFont.SetFillColor( rCol );
519 0 : SetPointFont(*this, aFont);
520 0 : aFont = GetFont();
521 0 : aFont.SetFillColor( rCol );
522 0 : pOutWin->SetFont( aFont );
523 0 : pTextEngine->SetFont( aFont );
524 :
525 0 : aSyntaxIdle.SetPriority( SchedulerPriority::LOWER );
526 0 : aSyntaxIdle.SetIdleHdl( LINK( this, SwSrcEditWindow, SyntaxTimerHdl ) );
527 :
528 0 : pTextEngine->EnableUndo( true );
529 0 : pTextEngine->SetUpdateMode( true );
530 :
531 0 : pTextView->ShowCursor( true, true );
532 0 : InitScrollBars();
533 0 : StartListening( *pTextEngine );
534 :
535 0 : SfxBindings& rBind = GetSrcView()->GetViewFrame()->GetBindings();
536 0 : rBind.Invalidate( SID_TABLE_CELL );
537 0 : }
538 :
539 0 : void SwSrcEditWindow::SetScrollBarRanges()
540 : {
541 : // Extra method, not InitScrollBars, because also for TextEngine events.
542 :
543 0 : pHScrollbar->SetRange( Range( 0, nCurTextWidth-1 ) );
544 0 : pVScrollbar->SetRange( Range(0, pTextEngine->GetTextHeight()-1) );
545 0 : }
546 :
547 0 : void SwSrcEditWindow::InitScrollBars()
548 : {
549 0 : SetScrollBarRanges();
550 :
551 0 : Size aOutSz( pOutWin->GetOutputSizePixel() );
552 0 : pVScrollbar->SetVisibleSize( aOutSz.Height() );
553 0 : pVScrollbar->SetPageSize( aOutSz.Height() * 8 / 10 );
554 0 : pVScrollbar->SetLineSize( pOutWin->GetTextHeight() );
555 0 : pVScrollbar->SetThumbPos( pTextView->GetStartDocPos().Y() );
556 0 : pHScrollbar->SetVisibleSize( aOutSz.Width() );
557 0 : pHScrollbar->SetPageSize( aOutSz.Width() * 8 / 10 );
558 0 : pHScrollbar->SetLineSize( pOutWin->GetTextWidth(OUString('x')) );
559 0 : pHScrollbar->SetThumbPos( pTextView->GetStartDocPos().X() );
560 :
561 0 : }
562 :
563 0 : IMPL_LINK(SwSrcEditWindow, ScrollHdl, ScrollBar*, pScroll)
564 : {
565 0 : if(pScroll == pVScrollbar)
566 : {
567 0 : long nDiff = pTextView->GetStartDocPos().Y() - pScroll->GetThumbPos();
568 0 : GetTextView()->Scroll( 0, nDiff );
569 0 : pTextView->ShowCursor( false, true );
570 0 : pScroll->SetThumbPos( pTextView->GetStartDocPos().Y() );
571 : }
572 : else
573 : {
574 0 : long nDiff = pTextView->GetStartDocPos().X() - pScroll->GetThumbPos();
575 0 : GetTextView()->Scroll( nDiff, 0 );
576 0 : pTextView->ShowCursor( false, true );
577 0 : pScroll->SetThumbPos( pTextView->GetStartDocPos().X() );
578 : }
579 0 : GetSrcView()->GetViewFrame()->GetBindings().Invalidate( SID_TABLE_CELL );
580 0 : return 0;
581 : }
582 :
583 0 : IMPL_LINK_TYPED( SwSrcEditWindow, SyntaxTimerHdl, Idle *, pIdle, void )
584 : {
585 0 : tools::Time aSyntaxCheckStart( tools::Time::SYSTEM );
586 : SAL_WARN_IF(pTextView == 0, "sw", "No View yet, but syntax highlighting?!");
587 :
588 0 : bHighlighting = true;
589 0 : sal_uInt16 nCount = 0;
590 : // at first the region around the cursor is processed
591 0 : TextSelection aSel = pTextView->GetSelection();
592 0 : sal_uInt16 nCur = (sal_uInt16)aSel.GetStart().GetPara();
593 0 : if(nCur > 40)
594 0 : nCur -= 40;
595 : else
596 0 : nCur = 0;
597 0 : if(!aSyntaxLineTable.empty())
598 0 : for(sal_uInt16 i = 0; i < 80 && nCount < 40; i++, nCur++)
599 : {
600 0 : if(aSyntaxLineTable.find(nCur) != aSyntaxLineTable.end())
601 : {
602 0 : DoSyntaxHighlight( nCur );
603 0 : aSyntaxLineTable.erase( nCur );
604 0 : nCount++;
605 0 : if(aSyntaxLineTable.empty())
606 0 : break;
607 0 : if((tools::Time( tools::Time::SYSTEM ).GetTime() - aSyntaxCheckStart.GetTime()) > MAX_HIGHLIGHTTIME )
608 : {
609 0 : break;
610 : }
611 : }
612 : }
613 :
614 : // when there is still anything left by then, go on from the beginning
615 0 : while ( !aSyntaxLineTable.empty() && nCount < MAX_SYNTAX_HIGHLIGHT)
616 : {
617 0 : sal_uInt16 nLine = *aSyntaxLineTable.begin();
618 0 : DoSyntaxHighlight( nLine );
619 0 : aSyntaxLineTable.erase(nLine);
620 0 : nCount ++;
621 0 : if(tools::Time( tools::Time::SYSTEM ).GetTime() - aSyntaxCheckStart.GetTime() > MAX_HIGHLIGHTTIME)
622 : {
623 0 : break;
624 : }
625 : }
626 :
627 0 : if(!aSyntaxLineTable.empty() && !pIdle->IsActive())
628 0 : pIdle->Start();
629 : // SyntaxTimerHdl is called when text changed
630 : // => good opportunity to determine text width!
631 0 : long nPrevTextWidth = nCurTextWidth;
632 0 : nCurTextWidth = pTextEngine->CalcTextWidth() + 25; // kleine Toleranz
633 0 : if ( nCurTextWidth != nPrevTextWidth )
634 0 : SetScrollBarRanges();
635 0 : bHighlighting = false;
636 0 : }
637 :
638 0 : void SwSrcEditWindow::DoSyntaxHighlight( sal_uInt16 nPara )
639 : {
640 : // Because of DelayedSyntaxHighlight it could happen,
641 : // that the line doesn't exist anymore!
642 0 : if ( nPara < pTextEngine->GetParagraphCount() )
643 : {
644 0 : bool bTempModified = IsModified();
645 0 : pTextEngine->RemoveAttribs( nPara, true );
646 0 : OUString aSource( pTextEngine->GetText( nPara ) );
647 0 : pTextEngine->SetUpdateMode( false );
648 0 : ImpDoHighlight( aSource, nPara );
649 0 : TextView* pTmp = pTextEngine->GetActiveView();
650 0 : pTmp->SetAutoScroll(false);
651 0 : pTextEngine->SetActiveView(0);
652 0 : pTextEngine->SetUpdateMode( true );
653 0 : pTextEngine->SetActiveView(pTmp);
654 0 : pTmp->SetAutoScroll(true);
655 0 : pTmp->ShowCursor( false/*pTmp->IsAutoScroll()*/ );
656 :
657 0 : if(!bTempModified)
658 0 : ClearModifyFlag();
659 : }
660 0 : }
661 :
662 0 : void SwSrcEditWindow::DoDelayedSyntaxHighlight( sal_uInt16 nPara )
663 : {
664 0 : if ( !bHighlighting && bDoSyntaxHighlight )
665 : {
666 0 : aSyntaxLineTable.insert( nPara );
667 0 : aSyntaxIdle.Start();
668 : }
669 0 : }
670 :
671 0 : void SwSrcEditWindow::ImpDoHighlight( const OUString& rSource, sal_uInt16 nLineOff )
672 : {
673 0 : SwTextPortions aPortionList;
674 0 : lcl_Highlight(rSource, aPortionList);
675 :
676 0 : size_t nCount = aPortionList.size();
677 0 : if ( !nCount )
678 0 : return;
679 :
680 0 : SwTextPortion& rLast = aPortionList[nCount-1];
681 0 : if ( rLast.nStart > rLast.nEnd ) // Only until Bug from MD is resolved
682 : {
683 0 : nCount--;
684 0 : aPortionList.pop_back();
685 0 : if ( !nCount )
686 0 : return;
687 : }
688 :
689 : {
690 : // Only blanks and tabs have to be attributed along.
691 : // When two identical attributes are placed consecutively,
692 : // it optimises the TextEngine.
693 0 : sal_uInt16 nLastEnd = 0;
694 :
695 0 : for ( size_t i = 0; i < nCount; i++ )
696 : {
697 0 : SwTextPortion& r = aPortionList[i];
698 : SAL_WARN_IF(
699 : r.nLine != aPortionList[0].nLine, "sw.level2",
700 : "multiple lines after all?");
701 0 : if ( r.nStart > r.nEnd ) // only until Bug from MD is resolved
702 0 : continue;
703 :
704 0 : if ( r.nStart > nLastEnd )
705 : {
706 : // Can I rely on the fact that all except blank and tab
707 : // are being highlighted?!
708 0 : r.nStart = nLastEnd;
709 : }
710 0 : nLastEnd = r.nEnd+1;
711 0 : if ( ( i == (nCount-1) ) && ( r.nEnd < rSource.getLength() ) )
712 0 : r.nEnd = rSource.getLength();
713 : }
714 : }
715 :
716 0 : for ( size_t i = 0; i < aPortionList.size(); i++ )
717 : {
718 0 : SwTextPortion& r = aPortionList[i];
719 0 : if ( r.nStart > r.nEnd ) // only until Bug from MD is resolved
720 0 : continue;
721 0 : if(r.eType != svtools::HTMLSGML &&
722 0 : r.eType != svtools::HTMLCOMMENT &&
723 0 : r.eType != svtools::HTMLKEYWORD &&
724 0 : r.eType != svtools::HTMLUNKNOWN)
725 0 : r.eType = svtools::HTMLUNKNOWN;
726 0 : Color aColor((ColorData)SW_MOD()->GetColorConfig().GetColorValue((svtools::ColorConfigEntry)r.eType).nColor);
727 0 : sal_uInt16 nLine = nLineOff+r.nLine;
728 0 : pTextEngine->SetAttrib( TextAttribFontColor( aColor ), nLine, r.nStart, r.nEnd+1, true );
729 0 : }
730 : }
731 :
732 0 : void SwSrcEditWindow::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
733 : {
734 0 : if ( dynamic_cast<const TextHint*>(&rHint) )
735 : {
736 0 : const TextHint& rTextHint = static_cast<const TextHint&>(rHint);
737 0 : if( rTextHint.GetId() == TEXT_HINT_VIEWSCROLLED )
738 : {
739 0 : pHScrollbar->SetThumbPos( pTextView->GetStartDocPos().X() );
740 0 : pVScrollbar->SetThumbPos( pTextView->GetStartDocPos().Y() );
741 : }
742 0 : else if( rTextHint.GetId() == TEXT_HINT_TEXTHEIGHTCHANGED )
743 : {
744 0 : if ( (long)pTextEngine->GetTextHeight() < pOutWin->GetOutputSizePixel().Height() )
745 0 : pTextView->Scroll( 0, pTextView->GetStartDocPos().Y() );
746 0 : pVScrollbar->SetThumbPos( pTextView->GetStartDocPos().Y() );
747 0 : SetScrollBarRanges();
748 : }
749 0 : else if( ( rTextHint.GetId() == TEXT_HINT_PARAINSERTED ) ||
750 0 : ( rTextHint.GetId() == TEXT_HINT_PARACONTENTCHANGED ) )
751 : {
752 0 : DoDelayedSyntaxHighlight( (sal_uInt16)rTextHint.GetValue() );
753 : }
754 : }
755 0 : }
756 :
757 0 : void SwSrcEditWindow::Invalidate(InvalidateFlags )
758 : {
759 0 : pOutWin->Invalidate();
760 0 : Window::Invalidate();
761 0 : }
762 :
763 0 : void SwSrcEditWindow::Command( const CommandEvent& rCEvt )
764 : {
765 0 : switch(rCEvt.GetCommand())
766 : {
767 : case CommandEventId::Wheel:
768 : case CommandEventId::StartAutoScroll:
769 : case CommandEventId::AutoScroll:
770 : {
771 0 : const CommandWheelData* pWData = rCEvt.GetWheelData();
772 0 : if( !pWData || CommandWheelMode::ZOOM != pWData->GetMode() )
773 0 : HandleScrollCommand( rCEvt, pHScrollbar, pVScrollbar );
774 : }
775 0 : break;
776 : default:
777 0 : Window::Command(rCEvt);
778 : }
779 0 : }
780 :
781 0 : void SwSrcEditWindow::HandleWheelCommand( const CommandEvent& rCEvt )
782 : {
783 0 : pTextView->Command(rCEvt);
784 0 : HandleScrollCommand( rCEvt, pHScrollbar, pVScrollbar );
785 0 : }
786 :
787 0 : void SwSrcEditWindow::GetFocus()
788 : {
789 0 : pOutWin->GrabFocus();
790 0 : }
791 :
792 0 : static bool lcl_GetLanguagesForEncoding(rtl_TextEncoding eEnc, LanguageType aLanguages[])
793 : {
794 0 : switch(eEnc)
795 : {
796 : case RTL_TEXTENCODING_UTF7 :
797 : case RTL_TEXTENCODING_UTF8 :
798 : // don#t fill - all LANGUAGE_SYSTEM means unicode font has to be used
799 0 : break;
800 :
801 : case RTL_TEXTENCODING_ISO_8859_3:
802 : case RTL_TEXTENCODING_ISO_8859_1 :
803 : case RTL_TEXTENCODING_MS_1252 :
804 : case RTL_TEXTENCODING_APPLE_ROMAN :
805 : case RTL_TEXTENCODING_IBM_850 :
806 : case RTL_TEXTENCODING_ISO_8859_14 :
807 : case RTL_TEXTENCODING_ISO_8859_15 :
808 : //fill with western languages
809 0 : aLanguages[0] = LANGUAGE_GERMAN;
810 0 : aLanguages[1] = LANGUAGE_FRENCH;
811 0 : aLanguages[2] = LANGUAGE_ITALIAN;
812 0 : aLanguages[3] = LANGUAGE_SPANISH;
813 0 : break;
814 :
815 : case RTL_TEXTENCODING_IBM_865 :
816 : //scandinavian
817 0 : aLanguages[0] = LANGUAGE_FINNISH;
818 0 : aLanguages[1] = LANGUAGE_NORWEGIAN;
819 0 : aLanguages[2] = LANGUAGE_SWEDISH;
820 0 : aLanguages[3] = LANGUAGE_DANISH;
821 0 : break;
822 :
823 : case RTL_TEXTENCODING_ISO_8859_10 :
824 : case RTL_TEXTENCODING_ISO_8859_13 :
825 : case RTL_TEXTENCODING_ISO_8859_2 :
826 : case RTL_TEXTENCODING_IBM_852 :
827 : case RTL_TEXTENCODING_MS_1250 :
828 : case RTL_TEXTENCODING_APPLE_CENTEURO :
829 0 : aLanguages[0] = LANGUAGE_POLISH;
830 0 : aLanguages[1] = LANGUAGE_CZECH;
831 0 : aLanguages[2] = LANGUAGE_HUNGARIAN;
832 0 : aLanguages[3] = LANGUAGE_SLOVAK;
833 0 : break;
834 :
835 : case RTL_TEXTENCODING_ISO_8859_4 :
836 : case RTL_TEXTENCODING_IBM_775 :
837 : case RTL_TEXTENCODING_MS_1257 :
838 0 : aLanguages[0] = LANGUAGE_LATVIAN ;
839 0 : aLanguages[1] = LANGUAGE_LITHUANIAN;
840 0 : aLanguages[2] = LANGUAGE_ESTONIAN ;
841 0 : break;
842 :
843 0 : case RTL_TEXTENCODING_IBM_863 : aLanguages[0] = LANGUAGE_FRENCH_CANADIAN; break;
844 0 : case RTL_TEXTENCODING_APPLE_FARSI : aLanguages[0] = LANGUAGE_FARSI; break;
845 0 : case RTL_TEXTENCODING_APPLE_ROMANIAN:aLanguages[0] = LANGUAGE_ROMANIAN; break;
846 :
847 : case RTL_TEXTENCODING_IBM_861 :
848 : case RTL_TEXTENCODING_APPLE_ICELAND :
849 0 : aLanguages[0] = LANGUAGE_ICELANDIC;
850 0 : break;
851 :
852 0 : case RTL_TEXTENCODING_APPLE_CROATIAN:aLanguages[0] = LANGUAGE_CROATIAN; break;
853 :
854 : case RTL_TEXTENCODING_IBM_437 :
855 0 : case RTL_TEXTENCODING_ASCII_US : aLanguages[0] = LANGUAGE_ENGLISH; break;
856 :
857 : case RTL_TEXTENCODING_IBM_862 :
858 : case RTL_TEXTENCODING_MS_1255 :
859 : case RTL_TEXTENCODING_APPLE_HEBREW :
860 : case RTL_TEXTENCODING_ISO_8859_8 :
861 0 : aLanguages[0] = LANGUAGE_HEBREW;
862 0 : break;
863 :
864 : case RTL_TEXTENCODING_IBM_857 :
865 : case RTL_TEXTENCODING_MS_1254 :
866 : case RTL_TEXTENCODING_APPLE_TURKISH:
867 : case RTL_TEXTENCODING_ISO_8859_9 :
868 0 : aLanguages[0] = LANGUAGE_TURKISH;
869 0 : break;
870 :
871 : case RTL_TEXTENCODING_IBM_860 :
872 0 : aLanguages[0] = LANGUAGE_PORTUGUESE;
873 0 : break;
874 :
875 : case RTL_TEXTENCODING_IBM_869 :
876 : case RTL_TEXTENCODING_MS_1253 :
877 : case RTL_TEXTENCODING_APPLE_GREEK :
878 : case RTL_TEXTENCODING_ISO_8859_7 :
879 : case RTL_TEXTENCODING_IBM_737 :
880 0 : aLanguages[0] = LANGUAGE_GREEK;
881 0 : break;
882 :
883 : case RTL_TEXTENCODING_KOI8_R :
884 : case RTL_TEXTENCODING_ISO_8859_5 :
885 : case RTL_TEXTENCODING_IBM_855 :
886 : case RTL_TEXTENCODING_MS_1251 :
887 : case RTL_TEXTENCODING_IBM_866 :
888 : case RTL_TEXTENCODING_APPLE_CYRILLIC :
889 0 : aLanguages[0] = LANGUAGE_RUSSIAN;
890 0 : break;
891 :
892 : case RTL_TEXTENCODING_APPLE_UKRAINIAN:
893 : case RTL_TEXTENCODING_KOI8_U:
894 0 : aLanguages[0] = LANGUAGE_UKRAINIAN;
895 0 : break;
896 :
897 : case RTL_TEXTENCODING_IBM_864 :
898 : case RTL_TEXTENCODING_MS_1256 :
899 : case RTL_TEXTENCODING_ISO_8859_6 :
900 : case RTL_TEXTENCODING_APPLE_ARABIC :
901 0 : aLanguages[0] = LANGUAGE_ARABIC_SAUDI_ARABIA;
902 0 : break;
903 :
904 : case RTL_TEXTENCODING_APPLE_CHINTRAD :
905 : case RTL_TEXTENCODING_MS_950 :
906 : case RTL_TEXTENCODING_GBT_12345 :
907 : case RTL_TEXTENCODING_BIG5 :
908 : case RTL_TEXTENCODING_EUC_TW :
909 : case RTL_TEXTENCODING_BIG5_HKSCS :
910 0 : aLanguages[0] = LANGUAGE_CHINESE_TRADITIONAL;
911 0 : break;
912 :
913 : case RTL_TEXTENCODING_EUC_JP :
914 : case RTL_TEXTENCODING_ISO_2022_JP :
915 : case RTL_TEXTENCODING_JIS_X_0201 :
916 : case RTL_TEXTENCODING_JIS_X_0208 :
917 : case RTL_TEXTENCODING_JIS_X_0212 :
918 : case RTL_TEXTENCODING_APPLE_JAPANESE :
919 : case RTL_TEXTENCODING_MS_932 :
920 : case RTL_TEXTENCODING_SHIFT_JIS :
921 0 : aLanguages[0] = LANGUAGE_JAPANESE;
922 0 : break;
923 :
924 : case RTL_TEXTENCODING_GB_2312 :
925 : case RTL_TEXTENCODING_MS_936 :
926 : case RTL_TEXTENCODING_GBK :
927 : case RTL_TEXTENCODING_GB_18030 :
928 : case RTL_TEXTENCODING_APPLE_CHINSIMP :
929 : case RTL_TEXTENCODING_EUC_CN :
930 : case RTL_TEXTENCODING_ISO_2022_CN :
931 0 : aLanguages[0] = LANGUAGE_CHINESE_SIMPLIFIED;
932 0 : break;
933 :
934 : case RTL_TEXTENCODING_APPLE_KOREAN :
935 : case RTL_TEXTENCODING_MS_949 :
936 : case RTL_TEXTENCODING_EUC_KR :
937 : case RTL_TEXTENCODING_ISO_2022_KR :
938 : case RTL_TEXTENCODING_MS_1361 :
939 0 : aLanguages[0] = LANGUAGE_KOREAN;
940 0 : break;
941 :
942 : case RTL_TEXTENCODING_APPLE_THAI :
943 : case RTL_TEXTENCODING_MS_874 :
944 : case RTL_TEXTENCODING_TIS_620 :
945 0 : aLanguages[0] = LANGUAGE_THAI;
946 0 : break;
947 0 : default: aLanguages[0] = Application::GetSettings().GetUILanguageTag().getLanguageType();
948 : }
949 0 : return aLanguages[0] != LANGUAGE_SYSTEM;
950 : }
951 0 : void SwSrcEditWindow::SetFont()
952 : {
953 : OUString sFontName(
954 : officecfg::Office::Common::Font::SourceViewFont::FontName::get().
955 0 : get_value_or(OUString()));
956 0 : if(sFontName.isEmpty())
957 : {
958 : LanguageType aLanguages[5] =
959 : {
960 : LANGUAGE_SYSTEM, LANGUAGE_SYSTEM, LANGUAGE_SYSTEM, LANGUAGE_SYSTEM, LANGUAGE_SYSTEM
961 0 : };
962 0 : vcl::Font aFont;
963 0 : if(lcl_GetLanguagesForEncoding(eSourceEncoding, aLanguages))
964 : {
965 : //TODO: check for multiple languages
966 0 : aFont = OutputDevice::GetDefaultFont(DefaultFontType::FIXED, aLanguages[0], GetDefaultFontFlags::NONE, this);
967 : }
968 : else
969 0 : aFont = OutputDevice::GetDefaultFont(DefaultFontType::SANS_UNICODE,
970 0 : Application::GetSettings().GetLanguageTag().getLanguageType(), GetDefaultFontFlags::NONE, this);
971 0 : sFontName = aFont.GetName();
972 : }
973 : const SvxFontListItem* pFontListItem =
974 0 : static_cast<const SvxFontListItem* >(pSrcView->GetDocShell()->GetItem( SID_ATTR_CHAR_FONTLIST ));
975 0 : const FontList* pList = pFontListItem->GetFontList();
976 0 : vcl::FontInfo aInfo = pList->Get(sFontName,WEIGHT_NORMAL, ITALIC_NONE);
977 :
978 0 : const vcl::Font& rFont = GetTextEngine()->GetFont();
979 0 : vcl::Font aFont(aInfo);
980 0 : Size aSize(rFont.GetSize());
981 : //font height is stored in point and set in twip
982 0 : aSize.Height() =
983 0 : officecfg::Office::Common::Font::SourceViewFont::FontHeight::get() * 20;
984 0 : aFont.SetSize(pOutWin->LogicToPixel(aSize, MAP_TWIP));
985 0 : GetTextEngine()->SetFont( aFont );
986 0 : pOutWin->SetFont(aFont);
987 0 : }
988 :
989 0 : void SwSrcEditWindow::SetTextEncoding(rtl_TextEncoding eEncoding)
990 : {
991 0 : eSourceEncoding = eEncoding;
992 0 : SetFont();
993 177 : }
994 :
995 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|