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( vcl::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(true),
250 0 : bHighlighting(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 : vcl::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 : SfxDispatcher::ExecutePopup();
416 0 : break;
417 : case COMMAND_WHEEL:
418 : case COMMAND_STARTAUTOSCROLL:
419 : case COMMAND_AUTOSCROLL:
420 : {
421 0 : const CommandWheelData* pWData = rCEvt.GetWheelData();
422 0 : if( !pWData || CommandWheelMode::ZOOM != pWData->GetMode() )
423 : {
424 0 : ((SwSrcEditWindow*)GetParent())->HandleWheelCommand( rCEvt );
425 : }
426 : }
427 0 : break;
428 :
429 : default:
430 0 : if ( pTextView )
431 0 : pTextView->Command( rCEvt );
432 : else
433 0 : Window::Command(rCEvt);
434 : }
435 0 : }
436 :
437 0 : void TextViewOutWin::KeyInput( const KeyEvent& rKEvt )
438 : {
439 0 : bool bDone = false;
440 0 : SwSrcEditWindow* pSrcEditWin = (SwSrcEditWindow*)GetParent();
441 0 : bool bChange = !pSrcEditWin->IsReadonly() || !TextEngine::DoesKeyChangeText( rKEvt );
442 0 : if(bChange)
443 0 : bDone = pTextView->KeyInput( rKEvt );
444 :
445 0 : SfxBindings& rBindings = ((SwSrcEditWindow*)GetParent())->GetSrcView()->GetViewFrame()->GetBindings();
446 0 : if ( !bDone )
447 : {
448 0 : if ( !SfxViewShell::Current()->KeyInput( rKEvt ) )
449 0 : Window::KeyInput( rKEvt );
450 : }
451 : else
452 : {
453 0 : rBindings.Invalidate( SID_TABLE_CELL );
454 0 : if ( rKEvt.GetKeyCode().GetGroup() == KEYGROUP_CURSOR )
455 0 : rBindings.Update( SID_BASICIDE_STAT_POS );
456 0 : if (pSrcEditWin->GetTextEngine()->IsModified() )
457 : {
458 0 : rBindings.Invalidate( SID_SAVEDOC );
459 0 : rBindings.Invalidate( SID_DOC_MODIFIED );
460 : }
461 0 : if( rKEvt.GetKeyCode().GetCode() == KEY_INSERT )
462 0 : rBindings.Invalidate( SID_ATTR_INSERT );
463 : }
464 :
465 0 : rBindings.Invalidate( SID_CUT );
466 0 : rBindings.Invalidate( SID_COPY );
467 :
468 0 : SwDocShell* pDocShell = pSrcEditWin->GetSrcView()->GetDocShell();
469 0 : if(pSrcEditWin->GetTextEngine()->IsModified())
470 : {
471 0 : pDocShell->SetModified();
472 : }
473 0 : }
474 :
475 0 : void TextViewOutWin::Paint( const Rectangle& rRect )
476 : {
477 0 : pTextView->Paint( rRect );
478 0 : }
479 :
480 0 : void SwSrcEditWindow::CreateTextEngine()
481 : {
482 0 : const Color &rCol = GetSettings().GetStyleSettings().GetWindowColor();
483 0 : pOutWin = new TextViewOutWin(this, 0);
484 0 : pOutWin->SetBackground(Wallpaper(rCol));
485 0 : pOutWin->SetPointer(Pointer(POINTER_TEXT));
486 0 : pOutWin->Show();
487 :
488 : // create Scrollbars
489 0 : pHScrollbar = new ScrollBar(this, WB_3DLOOK |WB_HSCROLL|WB_DRAG);
490 0 : pHScrollbar->EnableRTL( false ); // --- RTL --- no mirroring for scrollbars
491 0 : pHScrollbar->SetScrollHdl(LINK(this, SwSrcEditWindow, ScrollHdl));
492 0 : pHScrollbar->Show();
493 :
494 0 : pVScrollbar = new ScrollBar(this, WB_3DLOOK |WB_VSCROLL|WB_DRAG);
495 0 : pVScrollbar->EnableRTL( false ); // --- RTL --- no mirroring for scrollbars
496 0 : pVScrollbar->SetScrollHdl(LINK(this, SwSrcEditWindow, ScrollHdl));
497 0 : pHScrollbar->EnableDrag();
498 0 : pVScrollbar->Show();
499 :
500 0 : pTextEngine = new ExtTextEngine;
501 0 : pTextView = new ExtTextView( pTextEngine, pOutWin );
502 0 : pTextView->SetAutoIndentMode(true);
503 0 : pOutWin->SetTextView(pTextView);
504 :
505 0 : pTextEngine->SetUpdateMode( false );
506 0 : pTextEngine->InsertView( pTextView );
507 :
508 0 : vcl::Font aFont;
509 0 : aFont.SetTransparent( false );
510 0 : aFont.SetFillColor( rCol );
511 0 : SetPointFont( aFont );
512 0 : aFont = GetFont();
513 0 : aFont.SetFillColor( rCol );
514 0 : pOutWin->SetFont( aFont );
515 0 : pTextEngine->SetFont( aFont );
516 :
517 0 : aSyntaxIdleTimer.SetTimeout( SYNTAX_HIGHLIGHT_TIMEOUT );
518 0 : aSyntaxIdleTimer.SetTimeoutHdl( LINK( this, SwSrcEditWindow, SyntaxTimerHdl ) );
519 :
520 0 : pTextEngine->EnableUndo( true );
521 0 : pTextEngine->SetUpdateMode( true );
522 :
523 0 : pTextView->ShowCursor( true, true );
524 0 : InitScrollBars();
525 0 : StartListening( *pTextEngine );
526 :
527 0 : SfxBindings& rBind = GetSrcView()->GetViewFrame()->GetBindings();
528 0 : rBind.Invalidate( SID_TABLE_CELL );
529 0 : }
530 :
531 0 : void SwSrcEditWindow::SetScrollBarRanges()
532 : {
533 : // Extra method, not InitScrollBars, because also for TextEngine events.
534 :
535 0 : pHScrollbar->SetRange( Range( 0, nCurTextWidth-1 ) );
536 0 : pVScrollbar->SetRange( Range(0, pTextEngine->GetTextHeight()-1) );
537 0 : }
538 :
539 0 : void SwSrcEditWindow::InitScrollBars()
540 : {
541 0 : SetScrollBarRanges();
542 :
543 0 : Size aOutSz( pOutWin->GetOutputSizePixel() );
544 0 : pVScrollbar->SetVisibleSize( aOutSz.Height() );
545 0 : pVScrollbar->SetPageSize( aOutSz.Height() * 8 / 10 );
546 0 : pVScrollbar->SetLineSize( pOutWin->GetTextHeight() );
547 0 : pVScrollbar->SetThumbPos( pTextView->GetStartDocPos().Y() );
548 0 : pHScrollbar->SetVisibleSize( aOutSz.Width() );
549 0 : pHScrollbar->SetPageSize( aOutSz.Width() * 8 / 10 );
550 0 : pHScrollbar->SetLineSize( pOutWin->GetTextWidth(OUString('x')) );
551 0 : pHScrollbar->SetThumbPos( pTextView->GetStartDocPos().X() );
552 :
553 0 : }
554 :
555 0 : IMPL_LINK(SwSrcEditWindow, ScrollHdl, ScrollBar*, pScroll)
556 : {
557 0 : if(pScroll == pVScrollbar)
558 : {
559 0 : long nDiff = pTextView->GetStartDocPos().Y() - pScroll->GetThumbPos();
560 0 : GetTextView()->Scroll( 0, nDiff );
561 0 : pTextView->ShowCursor( false, true );
562 0 : pScroll->SetThumbPos( pTextView->GetStartDocPos().Y() );
563 : }
564 : else
565 : {
566 0 : long nDiff = pTextView->GetStartDocPos().X() - pScroll->GetThumbPos();
567 0 : GetTextView()->Scroll( nDiff, 0 );
568 0 : pTextView->ShowCursor( false, true );
569 0 : pScroll->SetThumbPos( pTextView->GetStartDocPos().X() );
570 : }
571 0 : GetSrcView()->GetViewFrame()->GetBindings().Invalidate( SID_TABLE_CELL );
572 0 : return 0;
573 : }
574 :
575 0 : IMPL_LINK( SwSrcEditWindow, SyntaxTimerHdl, Timer *, pTimer )
576 : {
577 0 : tools::Time aSyntaxCheckStart( tools::Time::SYSTEM );
578 : SAL_WARN_IF(pTextView == 0, "sw", "No View yet, but syntax highlighting?!");
579 :
580 0 : bHighlighting = true;
581 0 : sal_uInt16 nCount = 0;
582 : // at first the region around the cursor is processed
583 0 : TextSelection aSel = pTextView->GetSelection();
584 0 : sal_uInt16 nCur = (sal_uInt16)aSel.GetStart().GetPara();
585 0 : if(nCur > 40)
586 0 : nCur -= 40;
587 : else
588 0 : nCur = 0;
589 0 : if(!aSyntaxLineTable.empty())
590 0 : for(sal_uInt16 i = 0; i < 80 && nCount < 40; i++, nCur++)
591 : {
592 0 : if(aSyntaxLineTable.find(nCur) != aSyntaxLineTable.end())
593 : {
594 0 : DoSyntaxHighlight( nCur );
595 0 : aSyntaxLineTable.erase( nCur );
596 0 : nCount++;
597 0 : if(aSyntaxLineTable.empty())
598 0 : break;
599 0 : if((tools::Time( tools::Time::SYSTEM ).GetTime() - aSyntaxCheckStart.GetTime()) > MAX_HIGHLIGHTTIME )
600 : {
601 0 : pTimer->SetTimeout( 2 * SYNTAX_HIGHLIGHT_TIMEOUT );
602 0 : break;
603 : }
604 : }
605 : }
606 :
607 : // when there is still anything left by then, go on from the beginning
608 0 : while ( !aSyntaxLineTable.empty() && nCount < MAX_SYNTAX_HIGHLIGHT)
609 : {
610 0 : sal_uInt16 nLine = *aSyntaxLineTable.begin();
611 0 : DoSyntaxHighlight( nLine );
612 0 : aSyntaxLineTable.erase(nLine);
613 0 : nCount ++;
614 0 : if(tools::Time( tools::Time::SYSTEM ).GetTime() - aSyntaxCheckStart.GetTime() > MAX_HIGHLIGHTTIME)
615 : {
616 0 : pTimer->SetTimeout( 2 * SYNTAX_HIGHLIGHT_TIMEOUT );
617 0 : break;
618 : }
619 : }
620 :
621 0 : if(!aSyntaxLineTable.empty() && !pTimer->IsActive())
622 0 : pTimer->Start();
623 : // SyntaxTimerHdl is called when text changed
624 : // => good opportunity to determine text width!
625 0 : long nPrevTextWidth = nCurTextWidth;
626 0 : nCurTextWidth = pTextEngine->CalcTextWidth() + 25; // kleine Toleranz
627 0 : if ( nCurTextWidth != nPrevTextWidth )
628 0 : SetScrollBarRanges();
629 0 : bHighlighting = false;
630 :
631 0 : return 0;
632 : }
633 :
634 0 : void SwSrcEditWindow::DoSyntaxHighlight( sal_uInt16 nPara )
635 : {
636 : // Because of DelayedSyntaxHighlight it could happen,
637 : // that the line doesn't exist anymore!
638 0 : if ( nPara < pTextEngine->GetParagraphCount() )
639 : {
640 0 : bool bTempModified = IsModified();
641 0 : pTextEngine->RemoveAttribs( nPara, true );
642 0 : OUString aSource( pTextEngine->GetText( nPara ) );
643 0 : pTextEngine->SetUpdateMode( false );
644 0 : ImpDoHighlight( aSource, nPara );
645 0 : TextView* pTmp = pTextEngine->GetActiveView();
646 0 : pTmp->SetAutoScroll(false);
647 0 : pTextEngine->SetActiveView(0);
648 0 : pTextEngine->SetUpdateMode( true );
649 0 : pTextEngine->SetActiveView(pTmp);
650 0 : pTmp->SetAutoScroll(true);
651 0 : pTmp->ShowCursor( false/*pTmp->IsAutoScroll()*/ );
652 :
653 0 : if(!bTempModified)
654 0 : ClearModifyFlag();
655 : }
656 0 : }
657 :
658 0 : void SwSrcEditWindow::DoDelayedSyntaxHighlight( sal_uInt16 nPara )
659 : {
660 0 : if ( !bHighlighting && bDoSyntaxHighlight )
661 : {
662 0 : aSyntaxLineTable.insert( nPara );
663 0 : aSyntaxIdleTimer.Start();
664 : }
665 0 : }
666 :
667 0 : void SwSrcEditWindow::ImpDoHighlight( const OUString& rSource, sal_uInt16 nLineOff )
668 : {
669 0 : SwTextPortions aPortionList;
670 0 : lcl_Highlight(rSource, aPortionList);
671 :
672 0 : size_t nCount = aPortionList.size();
673 0 : if ( !nCount )
674 0 : return;
675 :
676 0 : SwTextPortion& rLast = aPortionList[nCount-1];
677 0 : if ( rLast.nStart > rLast.nEnd ) // Only until Bug from MD is resolved
678 : {
679 0 : nCount--;
680 0 : aPortionList.pop_back();
681 0 : if ( !nCount )
682 0 : return;
683 : }
684 :
685 : {
686 : // Only blanks and tabs have to be attributed along.
687 : // When two identical attributes are placed consecutively,
688 : // it optimises the TextEngine.
689 0 : sal_uInt16 nLastEnd = 0;
690 :
691 0 : for ( size_t i = 0; i < nCount; i++ )
692 : {
693 0 : SwTextPortion& r = aPortionList[i];
694 : SAL_WARN_IF(
695 : r.nLine != aPortionList[0].nLine, "sw.level2",
696 : "multiple lines after all?");
697 0 : if ( r.nStart > r.nEnd ) // only until Bug from MD is resolved
698 0 : continue;
699 :
700 0 : if ( r.nStart > nLastEnd )
701 : {
702 : // Can I rely on the fact that all except blank and tab
703 : // are being highlighted?!
704 0 : r.nStart = nLastEnd;
705 : }
706 0 : nLastEnd = r.nEnd+1;
707 0 : if ( ( i == (nCount-1) ) && ( r.nEnd < rSource.getLength() ) )
708 0 : r.nEnd = rSource.getLength();
709 : }
710 : }
711 :
712 0 : for ( size_t i = 0; i < aPortionList.size(); i++ )
713 : {
714 0 : SwTextPortion& r = aPortionList[i];
715 0 : if ( r.nStart > r.nEnd ) // only until Bug from MD is resolved
716 0 : continue;
717 0 : if(r.eType != svtools::HTMLSGML &&
718 0 : r.eType != svtools::HTMLCOMMENT &&
719 0 : r.eType != svtools::HTMLKEYWORD &&
720 0 : r.eType != svtools::HTMLUNKNOWN)
721 0 : r.eType = svtools::HTMLUNKNOWN;
722 0 : Color aColor((ColorData)SW_MOD()->GetColorConfig().GetColorValue((svtools::ColorConfigEntry)r.eType).nColor);
723 0 : sal_uInt16 nLine = nLineOff+r.nLine;
724 0 : pTextEngine->SetAttrib( TextAttribFontColor( aColor ), nLine, r.nStart, r.nEnd+1, true );
725 0 : }
726 : }
727 :
728 0 : void SwSrcEditWindow::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
729 : {
730 0 : if ( dynamic_cast<const TextHint*>(&rHint) )
731 : {
732 0 : const TextHint& rTextHint = (const TextHint&)rHint;
733 0 : if( rTextHint.GetId() == TEXT_HINT_VIEWSCROLLED )
734 : {
735 0 : pHScrollbar->SetThumbPos( pTextView->GetStartDocPos().X() );
736 0 : pVScrollbar->SetThumbPos( pTextView->GetStartDocPos().Y() );
737 : }
738 0 : else if( rTextHint.GetId() == TEXT_HINT_TEXTHEIGHTCHANGED )
739 : {
740 0 : if ( (long)pTextEngine->GetTextHeight() < pOutWin->GetOutputSizePixel().Height() )
741 0 : pTextView->Scroll( 0, pTextView->GetStartDocPos().Y() );
742 0 : pVScrollbar->SetThumbPos( pTextView->GetStartDocPos().Y() );
743 0 : SetScrollBarRanges();
744 : }
745 0 : else if( ( rTextHint.GetId() == TEXT_HINT_PARAINSERTED ) ||
746 0 : ( rTextHint.GetId() == TEXT_HINT_PARACONTENTCHANGED ) )
747 : {
748 0 : DoDelayedSyntaxHighlight( (sal_uInt16)rTextHint.GetValue() );
749 : }
750 : }
751 0 : }
752 :
753 0 : void SwSrcEditWindow::Invalidate(sal_uInt16 )
754 : {
755 0 : pOutWin->Invalidate();
756 0 : Window::Invalidate();
757 :
758 0 : }
759 :
760 0 : void SwSrcEditWindow::Command( const CommandEvent& rCEvt )
761 : {
762 0 : switch(rCEvt.GetCommand())
763 : {
764 : case COMMAND_WHEEL:
765 : case COMMAND_STARTAUTOSCROLL:
766 : case COMMAND_AUTOSCROLL:
767 : {
768 0 : const CommandWheelData* pWData = rCEvt.GetWheelData();
769 0 : if( !pWData || CommandWheelMode::ZOOM != pWData->GetMode() )
770 0 : HandleScrollCommand( rCEvt, pHScrollbar, pVScrollbar );
771 : }
772 0 : break;
773 : default:
774 0 : Window::Command(rCEvt);
775 : }
776 0 : }
777 :
778 0 : void SwSrcEditWindow::HandleWheelCommand( const CommandEvent& rCEvt )
779 : {
780 0 : pTextView->Command(rCEvt);
781 0 : HandleScrollCommand( rCEvt, pHScrollbar, pVScrollbar );
782 0 : }
783 :
784 0 : void SwSrcEditWindow::GetFocus()
785 : {
786 0 : pOutWin->GrabFocus();
787 0 : }
788 :
789 0 : static bool lcl_GetLanguagesForEncoding(rtl_TextEncoding eEnc, LanguageType aLanguages[])
790 : {
791 0 : switch(eEnc)
792 : {
793 : case RTL_TEXTENCODING_UTF7 :
794 : case RTL_TEXTENCODING_UTF8 :
795 : // don#t fill - all LANGUAGE_SYSTEM means unicode font has to be used
796 0 : break;
797 :
798 : case RTL_TEXTENCODING_ISO_8859_3:
799 : case RTL_TEXTENCODING_ISO_8859_1 :
800 : case RTL_TEXTENCODING_MS_1252 :
801 : case RTL_TEXTENCODING_APPLE_ROMAN :
802 : case RTL_TEXTENCODING_IBM_850 :
803 : case RTL_TEXTENCODING_ISO_8859_14 :
804 : case RTL_TEXTENCODING_ISO_8859_15 :
805 : //fill with western languages
806 0 : aLanguages[0] = LANGUAGE_GERMAN;
807 0 : aLanguages[1] = LANGUAGE_FRENCH;
808 0 : aLanguages[2] = LANGUAGE_ITALIAN;
809 0 : aLanguages[3] = LANGUAGE_SPANISH;
810 0 : break;
811 :
812 : case RTL_TEXTENCODING_IBM_865 :
813 : //scandinavian
814 0 : aLanguages[0] = LANGUAGE_FINNISH;
815 0 : aLanguages[1] = LANGUAGE_NORWEGIAN;
816 0 : aLanguages[2] = LANGUAGE_SWEDISH;
817 0 : aLanguages[3] = LANGUAGE_DANISH;
818 0 : break;
819 :
820 : case RTL_TEXTENCODING_ISO_8859_10 :
821 : case RTL_TEXTENCODING_ISO_8859_13 :
822 : case RTL_TEXTENCODING_ISO_8859_2 :
823 : case RTL_TEXTENCODING_IBM_852 :
824 : case RTL_TEXTENCODING_MS_1250 :
825 : case RTL_TEXTENCODING_APPLE_CENTEURO :
826 0 : aLanguages[0] = LANGUAGE_POLISH;
827 0 : aLanguages[1] = LANGUAGE_CZECH;
828 0 : aLanguages[2] = LANGUAGE_HUNGARIAN;
829 0 : aLanguages[3] = LANGUAGE_SLOVAK;
830 0 : break;
831 :
832 : case RTL_TEXTENCODING_ISO_8859_4 :
833 : case RTL_TEXTENCODING_IBM_775 :
834 : case RTL_TEXTENCODING_MS_1257 :
835 0 : aLanguages[0] = LANGUAGE_LATVIAN ;
836 0 : aLanguages[1] = LANGUAGE_LITHUANIAN;
837 0 : aLanguages[2] = LANGUAGE_ESTONIAN ;
838 0 : break;
839 :
840 0 : case RTL_TEXTENCODING_IBM_863 : aLanguages[0] = LANGUAGE_FRENCH_CANADIAN; break;
841 0 : case RTL_TEXTENCODING_APPLE_FARSI : aLanguages[0] = LANGUAGE_FARSI; break;
842 0 : case RTL_TEXTENCODING_APPLE_ROMANIAN:aLanguages[0] = LANGUAGE_ROMANIAN; break;
843 :
844 : case RTL_TEXTENCODING_IBM_861 :
845 : case RTL_TEXTENCODING_APPLE_ICELAND :
846 0 : aLanguages[0] = LANGUAGE_ICELANDIC;
847 0 : break;
848 :
849 0 : case RTL_TEXTENCODING_APPLE_CROATIAN:aLanguages[0] = LANGUAGE_CROATIAN; break;
850 :
851 : case RTL_TEXTENCODING_IBM_437 :
852 0 : case RTL_TEXTENCODING_ASCII_US : aLanguages[0] = LANGUAGE_ENGLISH; break;
853 :
854 : case RTL_TEXTENCODING_IBM_862 :
855 : case RTL_TEXTENCODING_MS_1255 :
856 : case RTL_TEXTENCODING_APPLE_HEBREW :
857 : case RTL_TEXTENCODING_ISO_8859_8 :
858 0 : aLanguages[0] = LANGUAGE_HEBREW;
859 0 : break;
860 :
861 : case RTL_TEXTENCODING_IBM_857 :
862 : case RTL_TEXTENCODING_MS_1254 :
863 : case RTL_TEXTENCODING_APPLE_TURKISH:
864 : case RTL_TEXTENCODING_ISO_8859_9 :
865 0 : aLanguages[0] = LANGUAGE_TURKISH;
866 0 : break;
867 :
868 : case RTL_TEXTENCODING_IBM_860 :
869 0 : aLanguages[0] = LANGUAGE_PORTUGUESE;
870 0 : break;
871 :
872 : case RTL_TEXTENCODING_IBM_869 :
873 : case RTL_TEXTENCODING_MS_1253 :
874 : case RTL_TEXTENCODING_APPLE_GREEK :
875 : case RTL_TEXTENCODING_ISO_8859_7 :
876 : case RTL_TEXTENCODING_IBM_737 :
877 0 : aLanguages[0] = LANGUAGE_GREEK;
878 0 : break;
879 :
880 : case RTL_TEXTENCODING_KOI8_R :
881 : case RTL_TEXTENCODING_ISO_8859_5 :
882 : case RTL_TEXTENCODING_IBM_855 :
883 : case RTL_TEXTENCODING_MS_1251 :
884 : case RTL_TEXTENCODING_IBM_866 :
885 : case RTL_TEXTENCODING_APPLE_CYRILLIC :
886 0 : aLanguages[0] = LANGUAGE_RUSSIAN;
887 0 : break;
888 :
889 : case RTL_TEXTENCODING_APPLE_UKRAINIAN:
890 : case RTL_TEXTENCODING_KOI8_U:
891 0 : aLanguages[0] = LANGUAGE_UKRAINIAN;
892 0 : break;
893 :
894 : case RTL_TEXTENCODING_IBM_864 :
895 : case RTL_TEXTENCODING_MS_1256 :
896 : case RTL_TEXTENCODING_ISO_8859_6 :
897 : case RTL_TEXTENCODING_APPLE_ARABIC :
898 0 : aLanguages[0] = LANGUAGE_ARABIC_SAUDI_ARABIA;
899 0 : break;
900 :
901 : case RTL_TEXTENCODING_APPLE_CHINTRAD :
902 : case RTL_TEXTENCODING_MS_950 :
903 : case RTL_TEXTENCODING_GBT_12345 :
904 : case RTL_TEXTENCODING_BIG5 :
905 : case RTL_TEXTENCODING_EUC_TW :
906 : case RTL_TEXTENCODING_BIG5_HKSCS :
907 0 : aLanguages[0] = LANGUAGE_CHINESE_TRADITIONAL;
908 0 : break;
909 :
910 : case RTL_TEXTENCODING_EUC_JP :
911 : case RTL_TEXTENCODING_ISO_2022_JP :
912 : case RTL_TEXTENCODING_JIS_X_0201 :
913 : case RTL_TEXTENCODING_JIS_X_0208 :
914 : case RTL_TEXTENCODING_JIS_X_0212 :
915 : case RTL_TEXTENCODING_APPLE_JAPANESE :
916 : case RTL_TEXTENCODING_MS_932 :
917 : case RTL_TEXTENCODING_SHIFT_JIS :
918 0 : aLanguages[0] = LANGUAGE_JAPANESE;
919 0 : break;
920 :
921 : case RTL_TEXTENCODING_GB_2312 :
922 : case RTL_TEXTENCODING_MS_936 :
923 : case RTL_TEXTENCODING_GBK :
924 : case RTL_TEXTENCODING_GB_18030 :
925 : case RTL_TEXTENCODING_APPLE_CHINSIMP :
926 : case RTL_TEXTENCODING_EUC_CN :
927 : case RTL_TEXTENCODING_ISO_2022_CN :
928 0 : aLanguages[0] = LANGUAGE_CHINESE_SIMPLIFIED;
929 0 : break;
930 :
931 : case RTL_TEXTENCODING_APPLE_KOREAN :
932 : case RTL_TEXTENCODING_MS_949 :
933 : case RTL_TEXTENCODING_EUC_KR :
934 : case RTL_TEXTENCODING_ISO_2022_KR :
935 : case RTL_TEXTENCODING_MS_1361 :
936 0 : aLanguages[0] = LANGUAGE_KOREAN;
937 0 : break;
938 :
939 : case RTL_TEXTENCODING_APPLE_THAI :
940 : case RTL_TEXTENCODING_MS_874 :
941 : case RTL_TEXTENCODING_TIS_620 :
942 0 : aLanguages[0] = LANGUAGE_THAI;
943 0 : break;
944 0 : default: aLanguages[0] = Application::GetSettings().GetUILanguageTag().getLanguageType();
945 : }
946 0 : return aLanguages[0] != LANGUAGE_SYSTEM;
947 : }
948 0 : void SwSrcEditWindow::SetFont()
949 : {
950 : OUString sFontName(
951 : officecfg::Office::Common::Font::SourceViewFont::FontName::get().
952 0 : get_value_or(OUString()));
953 0 : if(sFontName.isEmpty())
954 : {
955 : LanguageType aLanguages[5] =
956 : {
957 : LANGUAGE_SYSTEM, LANGUAGE_SYSTEM, LANGUAGE_SYSTEM, LANGUAGE_SYSTEM, LANGUAGE_SYSTEM
958 0 : };
959 0 : vcl::Font aFont;
960 0 : if(lcl_GetLanguagesForEncoding(eSourceEncoding, aLanguages))
961 : {
962 : //TODO: check for multiple languages
963 0 : aFont = OutputDevice::GetDefaultFont(DEFAULTFONT_FIXED, aLanguages[0], 0, this);
964 : }
965 : else
966 0 : aFont = OutputDevice::GetDefaultFont(DEFAULTFONT_SANS_UNICODE,
967 0 : Application::GetSettings().GetLanguageTag().getLanguageType(), 0, this);
968 0 : sFontName = aFont.GetName();
969 : }
970 : const SvxFontListItem* pFontListItem =
971 0 : (const SvxFontListItem* )pSrcView->GetDocShell()->GetItem( SID_ATTR_CHAR_FONTLIST );
972 0 : const FontList* pList = pFontListItem->GetFontList();
973 0 : vcl::FontInfo aInfo = pList->Get(sFontName,WEIGHT_NORMAL, ITALIC_NONE);
974 :
975 0 : const vcl::Font& rFont = GetTextEngine()->GetFont();
976 0 : vcl::Font aFont(aInfo);
977 0 : Size aSize(rFont.GetSize());
978 : //font height is stored in point and set in twip
979 0 : aSize.Height() =
980 0 : officecfg::Office::Common::Font::SourceViewFont::FontHeight::get() * 20;
981 0 : aFont.SetSize(pOutWin->LogicToPixel(aSize, MAP_TWIP));
982 0 : GetTextEngine()->SetFont( aFont );
983 0 : pOutWin->SetFont(aFont);
984 0 : }
985 :
986 0 : void SwSrcEditWindow::SetTextEncoding(rtl_TextEncoding eEncoding)
987 : {
988 0 : eSourceEncoding = eEncoding;
989 0 : SetFont();
990 270 : }
991 :
992 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|