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