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 <com/sun/star/accessibility/XAccessible.hpp>
21 : #include <com/sun/star/accessibility/AccessibleEventObject.hpp>
22 : #include <com/sun/star/accessibility/AccessibleEventId.hpp>
23 : #include <com/sun/star/accessibility/AccessibleStateType.hpp>
24 : #include <toolkit/helper/vclunohelper.hxx>
25 :
26 :
27 : #include "starmath.hrc"
28 :
29 : #include <vcl/menu.hxx>
30 : #include <vcl/settings.hxx>
31 :
32 : #include <editeng/editview.hxx>
33 : #include <editeng/editeng.hxx>
34 : #include <editeng/editstat.hxx>
35 : #include <editeng/eeitem.hxx>
36 : #include <sfx2/dispatch.hxx>
37 : #include <svl/intitem.hxx>
38 : #include <svl/itempool.hxx>
39 : #include <svl/stritem.hxx>
40 : #include <editeng/fhgtitem.hxx>
41 : #include <editeng/wghtitem.hxx>
42 : #include <editeng/lrspitem.hxx>
43 : #include <svl/itemset.hxx>
44 : #include <editeng/fontitem.hxx>
45 : #include <sfx2/viewfrm.hxx>
46 :
47 : #include "edit.hxx"
48 : #include "view.hxx"
49 : #include "document.hxx"
50 : #include "cfgitem.hxx"
51 : #include "accessibility.hxx"
52 : #include <memory>
53 :
54 : #define SCROLL_LINE 24
55 :
56 :
57 : using namespace com::sun::star::accessibility;
58 : using namespace com::sun::star;
59 : using namespace com::sun::star::uno;
60 :
61 :
62 :
63 :
64 24 : void SmGetLeftSelectionPart(const ESelection &rSel,
65 : sal_Int32 &nPara, sal_uInt16 &nPos)
66 : // returns paragraph number and position of the selections left part
67 : {
68 : // compare start and end of selection and use the one that comes first
69 24 : if ( rSel.nStartPara < rSel.nEndPara
70 24 : || (rSel.nStartPara == rSel.nEndPara && rSel.nStartPos < rSel.nEndPos) )
71 0 : { nPara = rSel.nStartPara;
72 0 : nPos = rSel.nStartPos;
73 : }
74 : else
75 24 : { nPara = rSel.nEndPara;
76 24 : nPos = rSel.nEndPos;
77 : }
78 24 : }
79 :
80 69 : bool SmEditWindow::IsInlineEditEnabled()
81 : {
82 69 : SmViewShell *pView = GetView();
83 69 : return pView && pView->IsInlineEditEnabled();
84 : }
85 :
86 :
87 :
88 25 : SmEditWindow::SmEditWindow( SmCmdBoxWindow &rMyCmdBoxWin ) :
89 : Window (&rMyCmdBoxWin),
90 : DropTargetHelper ( this ),
91 25 : rCmdBox (rMyCmdBoxWin)
92 : {
93 25 : SetHelpId(HID_SMA_COMMAND_WIN_EDIT);
94 25 : SetMapMode(MAP_PIXEL);
95 :
96 : // Even RTL languages don't use RTL for math
97 25 : EnableRTL( false );
98 :
99 25 : ApplyColorConfigValues( SM_MOD()->GetColorConfig() );
100 :
101 : // compare DataChanged
102 25 : SetBackground( GetSettings().GetStyleSettings().GetWindowColor() );
103 :
104 25 : aModifyIdle.SetIdleHdl(LINK(this, SmEditWindow, ModifyTimerHdl));
105 25 : aModifyIdle.SetPriority(SchedulerPriority::LOWEST);
106 :
107 25 : if (!IsInlineEditEnabled())
108 : {
109 25 : aCursorMoveIdle.SetIdleHdl(LINK(this, SmEditWindow, CursorMoveTimerHdl));
110 25 : aCursorMoveIdle.SetPriority(SchedulerPriority::LOWEST);
111 : }
112 :
113 : // if not called explicitly the this edit window within the
114 : // command window will just show an empty gray panel.
115 25 : Show();
116 25 : }
117 :
118 :
119 75 : SmEditWindow::~SmEditWindow()
120 : {
121 25 : disposeOnce();
122 50 : }
123 :
124 25 : void SmEditWindow::dispose()
125 : {
126 25 : aModifyIdle.Stop();
127 :
128 25 : StartCursorMove();
129 :
130 : // clean up of classes used for accessibility
131 : // must be done before EditView (and thus EditEngine) is no longer
132 : // available for those classes.
133 25 : if (mxAccessible.is())
134 : {
135 2 : mxAccessible->ClearWin(); // make Accessible defunctional
136 2 : mxAccessible.clear();
137 : }
138 :
139 25 : if (pEditView)
140 : {
141 25 : EditEngine *pEditEngine = pEditView->GetEditEngine();
142 25 : if (pEditEngine)
143 : {
144 25 : pEditEngine->SetStatusEventHdl( Link<>() );
145 25 : pEditEngine->RemoveView( pEditView.get() );
146 : }
147 25 : pEditView.reset();
148 : }
149 :
150 25 : pHScrollBar.disposeAndClear();
151 25 : pVScrollBar.disposeAndClear();
152 25 : pScrollBox.disposeAndClear();
153 :
154 25 : vcl::Window::dispose();
155 25 : }
156 :
157 28 : void SmEditWindow::StartCursorMove()
158 : {
159 28 : if (!IsInlineEditEnabled())
160 28 : aCursorMoveIdle.Stop();
161 28 : }
162 :
163 0 : void SmEditWindow::InvalidateSlots()
164 : {
165 0 : SfxBindings& rBind = GetView()->GetViewFrame()->GetBindings();
166 0 : rBind.Invalidate(SID_COPY);
167 0 : rBind.Invalidate(SID_CUT);
168 0 : rBind.Invalidate(SID_DELETE);
169 0 : }
170 :
171 89 : SmViewShell * SmEditWindow::GetView()
172 : {
173 89 : return rCmdBox.GetView();
174 : }
175 :
176 :
177 28 : SmDocShell * SmEditWindow::GetDoc()
178 : {
179 28 : SmViewShell *pView = rCmdBox.GetView();
180 28 : return pView ? pView->GetDoc() : 0;
181 : }
182 :
183 62 : EditView * SmEditWindow::GetEditView()
184 : {
185 62 : return pEditView.get();
186 : }
187 :
188 401 : EditEngine * SmEditWindow::GetEditEngine()
189 : {
190 401 : EditEngine *pEditEng = 0;
191 401 : if (pEditView)
192 376 : pEditEng = pEditView->GetEditEngine();
193 : else
194 : {
195 25 : SmDocShell *pDoc = GetDoc();
196 25 : if (pDoc)
197 25 : pEditEng = &pDoc->GetEditEngine();
198 : }
199 401 : return pEditEng;
200 : }
201 :
202 :
203 0 : SfxItemPool * SmEditWindow::GetEditEngineItemPool()
204 : {
205 0 : SmDocShell *pDoc = GetDoc();
206 0 : return pDoc ? &pDoc->GetEditEngineItemPool() : 0;
207 : }
208 :
209 25 : void SmEditWindow::ApplyColorConfigValues( const svtools::ColorConfig &rColorCfg )
210 : {
211 : // Note: SetBackground still done in SmEditWindow::DataChanged
212 : #if OSL_DEBUG_LEVEL > 1
213 : // ColorData nVal = rColorCfg.GetColorValue(svtools::FONTCOLOR).nColor;
214 : #endif
215 25 : SetTextColor( rColorCfg.GetColorValue(svtools::FONTCOLOR).nColor );
216 25 : Invalidate();
217 25 : }
218 :
219 0 : void SmEditWindow::DataChanged( const DataChangedEvent& )
220 : {
221 0 : const StyleSettings aSettings( GetSettings().GetStyleSettings() );
222 :
223 : // FIXME RenderContext
224 :
225 0 : ApplyColorConfigValues( SM_MOD()->GetColorConfig() );
226 0 : SetBackground( aSettings.GetWindowColor() );
227 :
228 : // edit fields in other Applications use this font instead of
229 : // the application font thus we use this one too
230 0 : SetPointFont(*this, aSettings.GetFieldFont() /*aSettings.GetAppFont()*/);
231 :
232 0 : EditEngine *pEditEngine = GetEditEngine();
233 0 : SfxItemPool *pEditEngineItemPool = GetEditEngineItemPool();
234 :
235 0 : if (pEditEngine && pEditEngineItemPool)
236 : {
237 : //!
238 : //! see also SmDocShell::GetEditEngine() !
239 : //!
240 :
241 0 : pEditEngine->SetDefTab(sal_uInt16(GetTextWidth(OUString("XXXX"))));
242 :
243 0 : SetEditEngineDefaultFonts(*pEditEngineItemPool);
244 :
245 : // forces new settings to be used
246 : // unfortunately this resets the whole edit engine
247 : // thus we need to save at least the text
248 0 : OUString aTxt( pEditEngine->GetText( LINEEND_LF ) );
249 0 : pEditEngine->Clear(); //incorrect font size
250 0 : pEditEngine->SetText( aTxt );
251 : }
252 :
253 0 : AdjustScrollBars();
254 0 : Resize();
255 0 : }
256 :
257 4 : IMPL_LINK_NOARG_TYPED( SmEditWindow, ModifyTimerHdl, Idle *, void )
258 : {
259 2 : UpdateStatus();
260 2 : aModifyIdle.Stop();
261 2 : }
262 :
263 0 : IMPL_LINK_NOARG_TYPED(SmEditWindow, CursorMoveTimerHdl, Idle *, void)
264 : // every once in a while check cursor position (selection) of edit
265 : // window and if it has changed (try to) set the formula-cursor
266 : // according to that.
267 : {
268 0 : if (IsInlineEditEnabled())
269 0 : return;
270 :
271 0 : ESelection aNewSelection(GetSelection());
272 :
273 0 : if (!aNewSelection.IsEqual(aOldSelection))
274 : {
275 0 : SmViewShell *pView = rCmdBox.GetView();
276 0 : if (pView)
277 : {
278 : // get row and column to look for
279 : sal_Int32 nRow;
280 : sal_uInt16 nCol;
281 0 : SmGetLeftSelectionPart(aNewSelection, nRow, nCol);
282 0 : nRow++;
283 0 : nCol++;
284 0 : pView->GetGraphicWindow().SetCursorPos(static_cast<sal_uInt16>(nRow), nCol);
285 0 : aOldSelection = aNewSelection;
286 : }
287 : }
288 0 : aCursorMoveIdle.Stop();
289 : }
290 :
291 63 : void SmEditWindow::Resize()
292 : {
293 63 : if (!pEditView)
294 25 : CreateEditView();
295 :
296 63 : if (pEditView)
297 : {
298 63 : pEditView->SetOutputArea(AdjustScrollBars());
299 63 : pEditView->ShowCursor();
300 :
301 : OSL_ENSURE( pEditView->GetEditEngine(), "EditEngine missing" );
302 63 : const long nMaxVisAreaStart = pEditView->GetEditEngine()->GetTextHeight() -
303 63 : pEditView->GetOutputArea().GetHeight();
304 63 : if (pEditView->GetVisArea().Top() > nMaxVisAreaStart)
305 : {
306 34 : Rectangle aVisArea(pEditView->GetVisArea() );
307 34 : aVisArea.Top() = (nMaxVisAreaStart > 0 ) ? nMaxVisAreaStart : 0;
308 34 : aVisArea.SetSize(pEditView->GetOutputArea().GetSize());
309 34 : pEditView->SetVisArea(aVisArea);
310 34 : pEditView->ShowCursor();
311 : }
312 63 : InitScrollBars();
313 : }
314 63 : Invalidate();
315 63 : }
316 :
317 0 : void SmEditWindow::MouseButtonUp(const MouseEvent &rEvt)
318 : {
319 0 : if (pEditView)
320 0 : pEditView->MouseButtonUp(rEvt);
321 : else
322 0 : Window::MouseButtonUp (rEvt);
323 :
324 0 : if (!IsInlineEditEnabled())
325 0 : CursorMoveTimerHdl(&aCursorMoveIdle);
326 0 : InvalidateSlots();
327 0 : }
328 :
329 0 : void SmEditWindow::MouseButtonDown(const MouseEvent &rEvt)
330 : {
331 0 : if (pEditView)
332 0 : pEditView->MouseButtonDown(rEvt);
333 : else
334 0 : Window::MouseButtonDown (rEvt);
335 :
336 0 : GrabFocus();
337 0 : }
338 :
339 0 : void SmEditWindow::Command(const CommandEvent& rCEvt)
340 : {
341 0 : bool bForwardEvt = true;
342 0 : if (rCEvt.GetCommand() == CommandEventId::ContextMenu)
343 : {
344 0 : GetParent()->ToTop();
345 :
346 0 : Point aPoint = rCEvt.GetMousePosPixel();
347 0 : std::unique_ptr<PopupMenu> xPopupMenu(new PopupMenu(SmResId(RID_COMMANDMENU)));
348 :
349 : // added for replaceability of context menus
350 0 : Menu* pMenu = NULL;
351 0 : ::com::sun::star::ui::ContextMenuExecuteEvent aEvent;
352 0 : aEvent.SourceWindow = VCLUnoHelper::GetInterface( this );
353 0 : aEvent.ExecutePosition.X = aPoint.X();
354 0 : aEvent.ExecutePosition.Y = aPoint.Y();
355 0 : OUString sDummy;
356 0 : if ( GetView()->TryContextMenuInterception( *xPopupMenu, sDummy, pMenu, aEvent ) )
357 : {
358 0 : if ( pMenu )
359 : {
360 0 : xPopupMenu.reset(static_cast<PopupMenu*>(pMenu));
361 : }
362 : }
363 :
364 0 : xPopupMenu->SetSelectHdl(LINK(this, SmEditWindow, MenuSelectHdl));
365 :
366 0 : xPopupMenu->Execute( this, aPoint );
367 0 : bForwardEvt = false;
368 : }
369 0 : else if (rCEvt.GetCommand() == CommandEventId::Wheel)
370 0 : bForwardEvt = !HandleWheelCommands( rCEvt );
371 :
372 0 : if (bForwardEvt)
373 : {
374 0 : if (pEditView)
375 0 : pEditView->Command( rCEvt );
376 : else
377 0 : Window::Command (rCEvt);
378 : }
379 0 : }
380 :
381 :
382 0 : bool SmEditWindow::HandleWheelCommands( const CommandEvent &rCEvt )
383 : {
384 0 : bool bCommandHandled = false; // true if the CommandEvent needs not
385 : // to be passed on (because it has fully
386 : // been taken care of).
387 :
388 0 : const CommandWheelData* pWData = rCEvt.GetWheelData();
389 0 : if (pWData)
390 : {
391 0 : if (CommandWheelMode::ZOOM == pWData->GetMode())
392 0 : bCommandHandled = true; // no zooming in Command window
393 : else
394 0 : bCommandHandled = HandleScrollCommand( rCEvt, pHScrollBar.get(), pVScrollBar.get());
395 : }
396 :
397 0 : return bCommandHandled;
398 : }
399 :
400 :
401 0 : IMPL_LINK( SmEditWindow, MenuSelectHdl, Menu *, pMenu )
402 : {
403 0 : SmViewShell *pViewSh = rCmdBox.GetView();
404 0 : if (pViewSh)
405 : pViewSh->GetViewFrame()->GetDispatcher()->Execute(
406 : SID_INSERTCOMMAND, SfxCallMode::RECORD,
407 0 : new SfxInt16Item(SID_INSERTCOMMAND, pMenu->GetCurItemId()), 0L);
408 0 : return 0;
409 : }
410 :
411 0 : void SmEditWindow::KeyInput(const KeyEvent& rKEvt)
412 : {
413 0 : if (rKEvt.GetKeyCode().GetCode() == KEY_ESCAPE)
414 : {
415 0 : bool bCallBase = true;
416 0 : SfxViewShell* pViewShell = GetView();
417 0 : if ( pViewShell && pViewShell->ISA(SmViewShell) )
418 : {
419 : // Terminate possible InPlace mode
420 0 : bCallBase = !pViewShell->Escape();
421 : }
422 0 : if ( bCallBase )
423 0 : Window::KeyInput( rKEvt );
424 : }
425 : else
426 : {
427 0 : StartCursorMove();
428 :
429 0 : bool autoClose = false;
430 0 : if (!pEditView)
431 0 : CreateEditView();
432 0 : ESelection aSelection = pEditView->GetSelection();
433 : // as we don't support RTL in Math, we need to swap values from selection when they were done
434 : // in RTL form
435 0 : aSelection.Adjust();
436 0 : OUString selected = pEditView->GetEditEngine()->GetText(aSelection);
437 :
438 0 : if (selected.trim() == "<?>")
439 0 : autoClose = true;
440 0 : else if (selected.isEmpty() && !aSelection.HasRange())
441 : {
442 0 : selected = pEditView->GetEditEngine()->GetText(aSelection.nEndPara);
443 0 : if (!selected.isEmpty())
444 : {
445 0 : sal_Int32 index = selected.indexOf("\n", aSelection.nEndPos);
446 0 : if (index != -1)
447 : {
448 0 : selected = selected.copy(index, sal_Int32(aSelection.nEndPos-index));
449 0 : if (selected.trim().isEmpty())
450 0 : autoClose = true;
451 : }
452 : else
453 : {
454 0 : sal_Int32 length = selected.getLength();
455 0 : if (aSelection.nEndPos == length)
456 0 : autoClose = true;
457 : else
458 : {
459 0 : selected = selected.copy(aSelection.nEndPos);
460 0 : if (selected.trim().isEmpty())
461 0 : autoClose = true;
462 : }
463 : }
464 : }
465 : else
466 0 : autoClose = true;
467 : }
468 :
469 0 : if ( !pEditView->PostKeyEvent(rKEvt) )
470 : {
471 0 : SmViewShell *pView = GetView();
472 0 : if ( pView && !pView->KeyInput(rKEvt) )
473 : {
474 : // F1 (help) leads to the destruction of this
475 0 : Flush();
476 0 : if ( aModifyIdle.IsActive() )
477 0 : aModifyIdle.Stop();
478 0 : Window::KeyInput(rKEvt);
479 : }
480 : else
481 : {
482 : // SFX has maybe called a slot of the view and thus (because of a hack in SFX)
483 : // set the focus to the view
484 0 : SfxViewShell* pVShell = GetView();
485 0 : if ( pVShell && pVShell->ISA(SmViewShell) &&
486 0 : static_cast<SmViewShell*>(pVShell)->GetGraphicWindow().HasFocus() )
487 : {
488 0 : GrabFocus();
489 : }
490 : }
491 : }
492 : else
493 : {
494 : // have doc-shell modified only for formula input/change and not
495 : // cursor travelling and such things...
496 0 : SmDocShell *pDocShell = GetDoc();
497 0 : EditEngine *pEditEngine = GetEditEngine();
498 0 : if (pDocShell && pEditEngine)
499 0 : pDocShell->SetModified(pEditEngine->IsModified());
500 0 : aModifyIdle.Start();
501 : }
502 :
503 : // get the current char of the key event
504 0 : sal_Unicode cCharCode = rKEvt.GetCharCode();
505 0 : OUString sClose;
506 :
507 0 : if (cCharCode == '{')
508 0 : sClose = " }";
509 0 : else if (cCharCode == '[')
510 0 : sClose = " ]";
511 0 : else if (cCharCode == '(')
512 0 : sClose = " )";
513 :
514 : // auto close the current character only when needed
515 0 : if (!sClose.isEmpty() && autoClose)
516 : {
517 0 : pEditView->InsertText(sClose);
518 : // position it at center of brackets
519 0 : aSelection.nStartPos += 2;
520 0 : aSelection.nEndPos = aSelection.nStartPos;
521 0 : pEditView->SetSelection(aSelection);
522 : }
523 :
524 0 : InvalidateSlots();
525 : }
526 0 : }
527 :
528 18 : void SmEditWindow::Paint(vcl::RenderContext& rRenderContext, const Rectangle& rRect)
529 : {
530 18 : if (!pEditView)
531 0 : CreateEditView();
532 18 : pEditView->Paint(rRect, &rRenderContext);
533 18 : }
534 :
535 25 : void SmEditWindow::CreateEditView()
536 : {
537 25 : EditEngine *pEditEngine = GetEditEngine();
538 :
539 : //! pEditEngine and pEditView may be 0.
540 : //! For example when the program is used by the document-converter
541 25 : if (!pEditView && pEditEngine)
542 : {
543 25 : pEditView.reset(new EditView(pEditEngine, this));
544 25 : pEditEngine->InsertView( pEditView.get() );
545 :
546 25 : if (!pVScrollBar)
547 25 : pVScrollBar = VclPtr<ScrollBar>::Create(this, WinBits(WB_VSCROLL));
548 25 : if (!pHScrollBar)
549 25 : pHScrollBar = VclPtr<ScrollBar>::Create(this, WinBits(WB_HSCROLL));
550 25 : if (!pScrollBox)
551 25 : pScrollBox = VclPtr<ScrollBarBox>::Create(this);
552 25 : pVScrollBar->SetScrollHdl(LINK(this, SmEditWindow, ScrollHdl));
553 25 : pHScrollBar->SetScrollHdl(LINK(this, SmEditWindow, ScrollHdl));
554 25 : pVScrollBar->EnableDrag( true );
555 25 : pHScrollBar->EnableDrag( true );
556 :
557 25 : pEditView->SetOutputArea(AdjustScrollBars());
558 :
559 25 : ESelection eSelection;
560 :
561 25 : pEditView->SetSelection(eSelection);
562 25 : Update();
563 25 : pEditView->ShowCursor(true, true);
564 :
565 25 : pEditEngine->SetStatusEventHdl( LINK(this, SmEditWindow, EditStatusHdl) );
566 25 : SetPointer(pEditView->GetPointer());
567 :
568 25 : SetScrollBarRanges();
569 : }
570 25 : }
571 :
572 :
573 12 : IMPL_LINK( SmEditWindow, EditStatusHdl, EditStatus *, /*pStat*/ )
574 : {
575 6 : if (!pEditView)
576 0 : return 1;
577 : else
578 : {
579 6 : Resize();
580 6 : return 0;
581 : }
582 : }
583 :
584 0 : IMPL_LINK( SmEditWindow, ScrollHdl, ScrollBar *, /*pScrollBar*/ )
585 : {
586 : OSL_ENSURE(pEditView, "EditView missing");
587 0 : if (pEditView)
588 : {
589 : pEditView->SetVisArea(Rectangle(Point(pHScrollBar->GetThumbPos(),
590 : pVScrollBar->GetThumbPos()),
591 0 : pEditView->GetVisArea().GetSize()));
592 0 : pEditView->Invalidate();
593 : }
594 0 : return 0;
595 : }
596 :
597 91 : Rectangle SmEditWindow::AdjustScrollBars()
598 : {
599 91 : const Size aOut( GetOutputSizePixel() );
600 91 : Point aPoint;
601 91 : Rectangle aRect( aPoint, aOut );
602 :
603 91 : if (pVScrollBar && pHScrollBar && pScrollBox)
604 : {
605 91 : const long nTmp = GetSettings().GetStyleSettings().GetScrollBarSize();
606 91 : Point aPt( aRect.TopRight() ); aPt.X() -= nTmp -1L;
607 91 : pVScrollBar->SetPosSizePixel( aPt, Size(nTmp, aOut.Height() - nTmp));
608 :
609 91 : aPt = aRect.BottomLeft(); aPt.Y() -= nTmp - 1L;
610 91 : pHScrollBar->SetPosSizePixel( aPt, Size(aOut.Width() - nTmp, nTmp));
611 :
612 91 : aPt.X() = pHScrollBar->GetSizePixel().Width();
613 91 : aPt.Y() = pVScrollBar->GetSizePixel().Height();
614 91 : pScrollBox->SetPosSizePixel(aPt, Size(nTmp, nTmp ));
615 :
616 91 : aRect.Right() = aPt.X() - 2;
617 91 : aRect.Bottom() = aPt.Y() - 2;
618 : }
619 91 : return aRect;
620 : }
621 :
622 88 : void SmEditWindow::SetScrollBarRanges()
623 : {
624 : // Extra method, not InitScrollBars, since it's also being used for EditEngine events
625 88 : EditEngine *pEditEngine = GetEditEngine();
626 88 : if (pVScrollBar && pHScrollBar && pEditEngine && pEditView)
627 : {
628 88 : long nTmp = pEditEngine->GetTextHeight();
629 88 : pVScrollBar->SetRange(Range(0, nTmp));
630 88 : pVScrollBar->SetThumbPos(pEditView->GetVisArea().Top());
631 :
632 88 : nTmp = pEditEngine->GetPaperSize().Width();
633 88 : pHScrollBar->SetRange(Range(0,nTmp));
634 88 : pHScrollBar->SetThumbPos(pEditView->GetVisArea().Left());
635 : }
636 88 : }
637 :
638 63 : void SmEditWindow::InitScrollBars()
639 : {
640 63 : if (pVScrollBar && pHScrollBar && pScrollBox && pEditView)
641 : {
642 63 : const Size aOut( pEditView->GetOutputArea().GetSize() );
643 63 : pVScrollBar->SetVisibleSize(aOut.Height());
644 63 : pVScrollBar->SetPageSize(aOut.Height() * 8 / 10);
645 63 : pVScrollBar->SetLineSize(aOut.Height() * 2 / 10);
646 :
647 63 : pHScrollBar->SetVisibleSize(aOut.Width());
648 63 : pHScrollBar->SetPageSize(aOut.Width() * 8 / 10);
649 63 : pHScrollBar->SetLineSize(SCROLL_LINE );
650 :
651 63 : SetScrollBarRanges();
652 :
653 63 : pVScrollBar->Show();
654 63 : pHScrollBar->Show();
655 63 : pScrollBox->Show();
656 : }
657 63 : }
658 :
659 :
660 24 : OUString SmEditWindow::GetText() const
661 : {
662 24 : OUString aText;
663 24 : EditEngine *pEditEngine = const_cast< SmEditWindow* >(this)->GetEditEngine();
664 : OSL_ENSURE( pEditEngine, "EditEngine missing" );
665 24 : if (pEditEngine)
666 24 : aText = pEditEngine->GetText( LINEEND_LF );
667 24 : return aText;
668 : }
669 :
670 :
671 4 : void SmEditWindow::SetText(const OUString& rText)
672 : {
673 4 : EditEngine *pEditEngine = GetEditEngine();
674 : OSL_ENSURE( pEditEngine, "EditEngine missing" );
675 4 : if (pEditEngine && !pEditEngine->IsModified())
676 : {
677 4 : if (!pEditView)
678 0 : CreateEditView();
679 :
680 4 : ESelection eSelection = pEditView->GetSelection();
681 :
682 4 : pEditEngine->SetText(rText);
683 4 : pEditEngine->ClearModifyFlag();
684 :
685 : // Restarting the timer here, prevents calling the handlers for other (currently inactive)
686 : // math tasks
687 4 : aModifyIdle.Start();
688 :
689 4 : pEditView->SetSelection(eSelection);
690 : }
691 4 : }
692 :
693 :
694 16 : void SmEditWindow::GetFocus()
695 : {
696 16 : Window::GetFocus();
697 :
698 16 : if (mxAccessible.is())
699 : {
700 : // Note: will implicitly send the AccessibleStateType::FOCUSED event
701 0 : ::accessibility::AccessibleTextHelper *pHelper = mxAccessible->GetTextHelper();
702 0 : if (pHelper)
703 0 : pHelper->SetFocus(true);
704 : }
705 :
706 16 : if (!pEditView)
707 0 : CreateEditView();
708 16 : EditEngine *pEditEngine = GetEditEngine();
709 16 : if (pEditEngine)
710 16 : pEditEngine->SetStatusEventHdl( LINK(this, SmEditWindow, EditStatusHdl) );
711 :
712 : //Let SmViewShell know we got focus
713 16 : if(GetView() && IsInlineEditEnabled())
714 0 : GetView()->SetInsertIntoEditWindow(true);
715 16 : }
716 :
717 :
718 1 : void SmEditWindow::LoseFocus()
719 : {
720 1 : EditEngine *pEditEngine = GetEditEngine();
721 1 : if (pEditEngine)
722 1 : pEditEngine->SetStatusEventHdl( Link<>() );
723 :
724 1 : Window::LoseFocus();
725 :
726 1 : if (mxAccessible.is())
727 : {
728 : // Note: will implicitly send the AccessibleStateType::FOCUSED event
729 0 : ::accessibility::AccessibleTextHelper *pHelper = mxAccessible->GetTextHelper();
730 0 : if (pHelper)
731 0 : pHelper->SetFocus(false);
732 : }
733 1 : }
734 :
735 :
736 0 : bool SmEditWindow::IsAllSelected() const
737 : {
738 0 : bool bRes = false;
739 0 : EditEngine *pEditEngine = (const_cast<SmEditWindow *>(this))->GetEditEngine();
740 : OSL_ENSURE( pEditView, "NULL pointer" );
741 : OSL_ENSURE( pEditEngine, "NULL pointer" );
742 0 : if (pEditEngine && pEditView)
743 : {
744 0 : ESelection eSelection( pEditView->GetSelection() );
745 0 : sal_Int32 nParaCnt = pEditEngine->GetParagraphCount();
746 0 : if (!(nParaCnt - 1))
747 : {
748 0 : sal_Int32 nTextLen = pEditEngine->GetText( LINEEND_LF ).getLength();
749 0 : bRes = !eSelection.nStartPos && (eSelection.nEndPos == nTextLen - 1);
750 : }
751 : else
752 : {
753 0 : bRes = !eSelection.nStartPara && (eSelection.nEndPara == nParaCnt - 1);
754 : }
755 : }
756 0 : return bRes;
757 : }
758 :
759 0 : void SmEditWindow::SelectAll()
760 : {
761 : OSL_ENSURE( pEditView, "NULL pointer" );
762 0 : if (pEditView)
763 : {
764 : // ALL as last two parameters refers to the end of the text
765 0 : pEditView->SetSelection( ESelection( 0, 0, EE_PARA_ALL, EE_TEXTPOS_ALL ) );
766 : }
767 0 : }
768 :
769 0 : void SmEditWindow::InsertCommand(sal_uInt16 nCommand)
770 : {
771 : OSL_ENSURE( pEditView, "EditView missing" );
772 0 : if (pEditView)
773 : {
774 0 : ESelection aSelection = pEditView->GetSelection();
775 :
776 : OSL_ENSURE( pEditView, "NULL pointer" );
777 0 : OUString aText = SM_RESSTR(nCommand);
778 :
779 0 : OUString aCurrentFormula = pEditView->GetEditEngine()->GetText();
780 0 : sal_Int32 nStartIndex = 0;
781 0 : sal_Int32 nEndIndex = 0;
782 :
783 : // get the start position (when we get a multi line formula)
784 0 : for (sal_Int32 nParaPos = 0; nParaPos < aSelection.nStartPara; nParaPos++)
785 0 : nStartIndex = aCurrentFormula.indexOf("\n", nStartIndex) + 1;
786 :
787 0 : nStartIndex += aSelection.nStartPos;
788 :
789 : // get the end position (when we get a multi line formula)
790 0 : for (sal_Int32 nParaPos = 0; nParaPos < aSelection.nEndPara; nParaPos++)
791 0 : nEndIndex = aCurrentFormula.indexOf("\n", nEndIndex) + 1;
792 :
793 0 : nEndIndex += aSelection.nEndPos;
794 :
795 : // remove right space of current symbol if there already is one
796 0 : if (nEndIndex < aCurrentFormula.getLength() &&
797 0 : aCurrentFormula[nEndIndex] == ' ')
798 0 : aText = aText.trim();
799 :
800 : // put a space before a new command if not in the beginning of a line
801 0 : if (aSelection.nStartPos > 0 && aCurrentFormula[nStartIndex - 1] != ' ')
802 0 : aText = " " + aText;
803 :
804 0 : pEditView->InsertText(aText);
805 :
806 : // Remember start of the selection and move the cursor there afterwards.
807 0 : aSelection.nEndPara = aSelection.nStartPara;
808 0 : if (HasMark(aText))
809 : {
810 0 : aSelection.nEndPos = aSelection.nStartPos;
811 0 : pEditView->SetSelection(aSelection);
812 0 : SelNextMark();
813 : }
814 : else
815 : { // set selection after inserted text
816 0 : aSelection.nEndPos = aSelection.nStartPos + aText.getLength();
817 0 : aSelection.nStartPos = aSelection.nEndPos;
818 0 : pEditView->SetSelection(aSelection);
819 : }
820 :
821 0 : aModifyIdle.Start();
822 0 : StartCursorMove();
823 0 : GrabFocus();
824 : }
825 0 : }
826 :
827 0 : void SmEditWindow::MarkError(const Point &rPos)
828 : {
829 : OSL_ENSURE( pEditView, "EditView missing" );
830 0 : if (pEditView)
831 : {
832 0 : const sal_uInt16 nCol = sal::static_int_cast< sal_uInt16 >(rPos.X());
833 0 : const sal_uInt16 nRow = sal::static_int_cast< sal_uInt16 >(rPos.Y() - 1);
834 :
835 0 : pEditView->SetSelection(ESelection(nRow, nCol - 1, nRow, nCol));
836 0 : GrabFocus();
837 : }
838 0 : }
839 :
840 : // Makes selection to next <?> symbol
841 3 : void SmEditWindow::SelNextMark()
842 : {
843 3 : EditEngine *pEditEngine = GetEditEngine();
844 : OSL_ENSURE( pEditView, "NULL pointer" );
845 : OSL_ENSURE( pEditEngine, "NULL pointer" );
846 3 : if (pEditEngine && pEditView)
847 : {
848 3 : ESelection eSelection = pEditView->GetSelection();
849 3 : sal_Int32 nPos = eSelection.nEndPos;
850 3 : sal_Int32 nCounts = pEditEngine->GetParagraphCount();
851 :
852 6 : while (eSelection.nEndPara < nCounts)
853 : {
854 3 : OUString aText = pEditEngine->GetText(eSelection.nEndPara);
855 3 : nPos = aText.indexOf("<?>", nPos);
856 3 : if (nPos != -1)
857 : {
858 : pEditView->SetSelection(ESelection(
859 3 : eSelection.nEndPara, nPos, eSelection.nEndPara, nPos + 3));
860 3 : break;
861 : }
862 :
863 0 : nPos = 0;
864 0 : eSelection.nEndPara++;
865 0 : }
866 : }
867 3 : }
868 :
869 1 : void SmEditWindow::SelPrevMark()
870 : {
871 1 : EditEngine *pEditEngine = GetEditEngine();
872 : OSL_ENSURE( pEditEngine, "NULL pointer" );
873 : OSL_ENSURE( pEditView, "NULL pointer" );
874 1 : if (pEditEngine && pEditView)
875 : {
876 1 : ESelection eSelection = pEditView->GetSelection();
877 1 : sal_Int32 nPos = -1;
878 1 : sal_Int32 nMax = eSelection.nStartPos;
879 1 : OUString aText(pEditEngine->GetText(eSelection.nStartPara));
880 2 : OUString aMark("<?>");
881 1 : sal_Int32 nCounts = pEditEngine->GetParagraphCount();
882 :
883 1 : do
884 : {
885 1 : sal_Int32 nMarkIndex = aText.indexOf(aMark);
886 3 : while ((nMarkIndex < nMax) && (nMarkIndex != -1))
887 : {
888 1 : nPos = nMarkIndex;
889 1 : nMarkIndex = aText.indexOf(aMark, nMarkIndex + 1);
890 : }
891 :
892 1 : if (nPos == -1)
893 : {
894 0 : eSelection.nStartPara--;
895 0 : aText = pEditEngine->GetText(eSelection.nStartPara);
896 0 : nMax = aText.getLength();
897 : }
898 : }
899 2 : while ((eSelection.nStartPara < nCounts) &&
900 : (nPos == -1));
901 :
902 1 : if (nPos != -1)
903 : {
904 : pEditView->SetSelection(ESelection(
905 1 : eSelection.nStartPara, nPos, eSelection.nStartPara, nPos + 3));
906 1 : }
907 : }
908 1 : }
909 :
910 3 : bool SmEditWindow::HasMark(const OUString& rText)
911 : // returns true iff 'rText' contains a mark
912 : {
913 3 : return rText.indexOf("<?>") != -1;
914 : }
915 :
916 0 : void SmEditWindow::MouseMove(const MouseEvent &rEvt)
917 : {
918 0 : if (pEditView)
919 0 : pEditView->MouseMove(rEvt);
920 0 : }
921 :
922 0 : sal_Int8 SmEditWindow::AcceptDrop( const AcceptDropEvent& /*rEvt*/ )
923 : {
924 0 : return DND_ACTION_NONE;
925 : }
926 :
927 0 : sal_Int8 SmEditWindow::ExecuteDrop( const ExecuteDropEvent& /*rEvt*/ )
928 : {
929 0 : return DND_ACTION_NONE;
930 : }
931 :
932 24 : ESelection SmEditWindow::GetSelection() const
933 : {
934 : // pointer may be 0 when reloading a document and the old view
935 : // was already destroyed
936 : //(OSL_ENSURE( pEditView, "NULL pointer" );
937 24 : ESelection eSel;
938 24 : if (pEditView)
939 24 : eSel = pEditView->GetSelection();
940 24 : return eSel;
941 : }
942 :
943 0 : void SmEditWindow::SetSelection(const ESelection &rSel)
944 : {
945 : OSL_ENSURE( pEditView, "NULL pointer" );
946 0 : if (pEditView)
947 0 : pEditView->SetSelection(rSel);
948 0 : InvalidateSlots();
949 0 : }
950 :
951 18 : bool SmEditWindow::IsEmpty() const
952 : {
953 18 : EditEngine *pEditEngine = (const_cast<SmEditWindow *>(this))->GetEditEngine();
954 18 : bool bEmpty = ( pEditEngine && pEditEngine->GetTextLen() == 0 );
955 18 : return bEmpty;
956 : }
957 :
958 36 : bool SmEditWindow::IsSelected() const
959 : {
960 36 : return pEditView && pEditView->HasSelection();
961 : }
962 :
963 :
964 5 : void SmEditWindow::UpdateStatus( bool bSetDocModified )
965 : {
966 5 : SmModule *pMod = SM_MOD();
967 5 : if (pMod && pMod->GetConfig()->IsAutoRedraw())
968 5 : Flush();
969 5 : if ( bSetDocModified )
970 3 : GetDoc()->SetModified(true);
971 5 : }
972 :
973 0 : void SmEditWindow::Cut()
974 : {
975 : OSL_ENSURE( pEditView, "EditView missing" );
976 0 : if (pEditView)
977 : {
978 0 : pEditView->Cut();
979 0 : UpdateStatus(true);
980 : }
981 0 : }
982 :
983 0 : void SmEditWindow::Copy()
984 : {
985 : OSL_ENSURE( pEditView, "EditView missing" );
986 0 : if (pEditView)
987 0 : pEditView->Copy();
988 0 : }
989 :
990 0 : void SmEditWindow::Paste()
991 : {
992 : OSL_ENSURE( pEditView, "EditView missing" );
993 0 : if (pEditView)
994 : {
995 0 : pEditView->Paste();
996 0 : UpdateStatus(true);
997 : }
998 0 : }
999 :
1000 3 : void SmEditWindow::Delete()
1001 : {
1002 : OSL_ENSURE( pEditView, "EditView missing" );
1003 3 : if (pEditView)
1004 : {
1005 3 : pEditView->DeleteSelected();
1006 3 : UpdateStatus(true);
1007 : }
1008 3 : }
1009 :
1010 3 : void SmEditWindow::InsertText(const OUString& rText)
1011 : {
1012 : OSL_ENSURE( pEditView, "EditView missing" );
1013 3 : if (pEditView)
1014 : {
1015 : // Note: Insertion of a space in front of commands is done here and
1016 : // in SmEditWindow::InsertCommand.
1017 3 : ESelection aSelection = pEditView->GetSelection();
1018 3 : OUString aCurrentFormula = pEditView->GetEditEngine()->GetText();
1019 3 : sal_Int32 nStartIndex = 0;
1020 3 : sal_Int32 nEndIndex = 0;
1021 :
1022 : // get the start position (when we get a multi line formula)
1023 3 : for (sal_Int32 nParaPos = 0; nParaPos < aSelection.nStartPara; nParaPos++)
1024 0 : nStartIndex = aCurrentFormula.indexOf("\n", nStartIndex) + 1;
1025 :
1026 3 : nStartIndex += aSelection.nStartPos;
1027 :
1028 : // get the end position (when we get a multi line formula)
1029 3 : for (sal_Int32 nParaPos = 0; nParaPos < aSelection.nEndPara; nParaPos++)
1030 0 : nEndIndex = aCurrentFormula.indexOf("\n", nEndIndex) + 1;
1031 :
1032 3 : nEndIndex += aSelection.nEndPos;
1033 :
1034 : // TODO: unify this function with the InsertCommand: The do the same thing for different
1035 : // callers
1036 6 : OUString string(rText);
1037 :
1038 : // put a space before a new command if not in the beginning of a line
1039 3 : if (aSelection.nStartPos > 0 && aCurrentFormula[nStartIndex - 1] != ' ')
1040 0 : string = " " + string;
1041 :
1042 : /*
1043 : fdo#65588 - Elements Dock: Scrollbar moves into input window
1044 : This change "solves" the visual problem. But I don't think so
1045 : this is the best solution.
1046 : */
1047 3 : pVScrollBar->Hide();
1048 3 : pHScrollBar->Hide();
1049 3 : pEditView->InsertText(string);
1050 3 : AdjustScrollBars();
1051 3 : pVScrollBar->Show();
1052 3 : pHScrollBar->Show();
1053 :
1054 : // Remember start of the selection and move the cursor there afterwards.
1055 3 : aSelection.nEndPara = aSelection.nStartPara;
1056 3 : if (HasMark(string))
1057 : {
1058 0 : aSelection.nEndPos = aSelection.nStartPos;
1059 0 : pEditView->SetSelection(aSelection);
1060 0 : SelNextMark();
1061 : }
1062 : else
1063 : { // set selection after inserted text
1064 3 : aSelection.nEndPos = aSelection.nStartPos + string.getLength();
1065 3 : aSelection.nStartPos = aSelection.nEndPos;
1066 3 : pEditView->SetSelection(aSelection);
1067 : }
1068 :
1069 3 : aModifyIdle.Start();
1070 3 : StartCursorMove();
1071 6 : GrabFocus();
1072 : }
1073 3 : }
1074 :
1075 8 : void SmEditWindow::Flush()
1076 : {
1077 8 : EditEngine *pEditEngine = GetEditEngine();
1078 8 : if (pEditEngine && pEditEngine->IsModified())
1079 : {
1080 4 : pEditEngine->ClearModifyFlag();
1081 4 : SmViewShell *pViewSh = rCmdBox.GetView();
1082 4 : if (pViewSh)
1083 : {
1084 : pViewSh->GetViewFrame()->GetDispatcher()->Execute(
1085 : SID_TEXT, SfxCallMode::RECORD,
1086 4 : new SfxStringItem(SID_TEXT, GetText()), 0L);
1087 : }
1088 : }
1089 8 : if (aCursorMoveIdle.IsActive())
1090 : {
1091 0 : aCursorMoveIdle.Stop();
1092 0 : CursorMoveTimerHdl(&aCursorMoveIdle);
1093 : }
1094 8 : }
1095 :
1096 0 : void SmEditWindow::DeleteEditView( SmViewShell & /*rView*/ )
1097 : {
1098 0 : if (pEditView)
1099 : {
1100 0 : std::unique_ptr<EditEngine> xEditEngine(pEditView->GetEditEngine());
1101 0 : if (xEditEngine)
1102 : {
1103 0 : xEditEngine->SetStatusEventHdl( Link<>() );
1104 0 : xEditEngine->RemoveView( pEditView.get() );
1105 : }
1106 0 : pEditView.reset();
1107 : }
1108 0 : }
1109 :
1110 2 : uno::Reference< XAccessible > SmEditWindow::CreateAccessible()
1111 : {
1112 2 : if (!mxAccessible.is())
1113 : {
1114 2 : mxAccessible.set(new SmEditAccessible( this ));
1115 2 : mxAccessible->Init();
1116 : }
1117 2 : return uno::Reference< XAccessible >(mxAccessible.get());
1118 42 : }
1119 :
1120 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|