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