xref: /trunk/main/starmath/source/edit.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_starmath.hxx"
30 
31 
32 #include <com/sun/star/accessibility/XAccessible.hpp>
33 #include <com/sun/star/accessibility/AccessibleEventObject.hpp>
34 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
35 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
36 #include <toolkit/helper/vclunohelper.hxx>
37 
38 
39 #include "starmath.hrc"
40 #define ITEMID_FONT         1
41 #define ITEMID_FONTHEIGHT   2
42 #define ITEMID_LRSPACE      3
43 #define ITEMID_WEIGHT       4
44 
45 
46 #include <vcl/menu.hxx>
47 #include <editeng/editview.hxx>
48 #include <editeng/editeng.hxx>
49 #include <editeng/editstat.hxx>
50 #include <editeng/eeitem.hxx>
51 #include <sfx2/dispatch.hxx>
52 #include <svl/intitem.hxx>
53 #include <svl/itempool.hxx>
54 #include <svl/stritem.hxx>
55 #include <editeng/fhgtitem.hxx>
56 #include <editeng/wghtitem.hxx>
57 #include <editeng/lrspitem.hxx>
58 #include <svl/itemset.hxx>
59 #include <editeng/fontitem.hxx>
60 #include <sfx2/viewfrm.hxx>
61 
62 #include "edit.hxx"
63 #include "view.hxx"
64 #include "document.hxx"
65 #include "config.hxx"
66 
67 #define SCROLL_LINE         24
68 
69 #define MINWIDTH        200
70 #define MINHEIGHT       200
71 #define MINSPLIT        40
72 #define SPLITTERWIDTH   2
73 
74 
75 using namespace com::sun::star::accessibility;
76 using namespace com::sun::star;
77 using namespace com::sun::star::uno;
78 
79 ////////////////////////////////////////
80 
81 
82 void SmGetLeftSelectionPart(const ESelection aSel,
83                             sal_uInt16 &nPara, sal_uInt16 &nPos)
84     // returns paragraph number and position of the selections left part
85 {
86     // compare start and end of selection and use the one that comes first
87     if (    aSel.nStartPara <  aSel.nEndPara
88         ||  (aSel.nStartPara == aSel.nEndPara  &&  aSel.nStartPos < aSel.nEndPos) )
89     {   nPara = aSel.nStartPara;
90         nPos  = aSel.nStartPos;
91     }
92     else
93     {   nPara = aSel.nEndPara;
94         nPos  = aSel.nEndPos;
95     }
96 }
97 
98 ////////////////////////////////////////
99 
100 SmEditWindow::SmEditWindow( SmCmdBoxWindow &rMyCmdBoxWin ) :
101     Window              (&rMyCmdBoxWin),
102     DropTargetHelper    ( this ),
103     pAccessible         (0),
104     rCmdBox             (rMyCmdBoxWin),
105     pEditView           (0),
106     pHScrollBar         (0),
107     pVScrollBar         (0),
108     pScrollBox          (0)
109 {
110     SetHelpId(HID_SMA_COMMAND_WIN_EDIT);
111     SetMapMode(MAP_PIXEL);
112 
113     // Even RTL languages don't use RTL for math
114     rCmdBox.GetEditWindow()->EnableRTL( sal_False );
115 
116     ApplyColorConfigValues( SM_MOD()->GetColorConfig() );
117 
118     // compare DataChanged
119     SetBackground( GetSettings().GetStyleSettings().GetWindowColor() );
120 
121     aModifyTimer.SetTimeoutHdl(LINK(this, SmEditWindow, ModifyTimerHdl));
122     aModifyTimer.SetTimeout(500);
123 
124     aCursorMoveTimer.SetTimeoutHdl(LINK(this, SmEditWindow, CursorMoveTimerHdl));
125     aCursorMoveTimer.SetTimeout(500);
126 
127     // if not called explicitly the this edit window within the
128     // command window will just show an empty gray panel.
129     Show();
130 }
131 
132 
133 SmEditWindow::~SmEditWindow()
134 {
135     aCursorMoveTimer.Stop();
136     aModifyTimer.Stop();
137 
138 
139     // #112565# clean up of classes used for accessibility
140     // must be done before EditView (and thus EditEngine) is no longer
141     // available for those classes.
142     if (pAccessible)
143         pAccessible->ClearWin();    // make Accessible defunctional
144     // Note: memory for pAccessible will be freed when the reference
145     // xAccessible is released.
146 
147     if (pEditView)
148     {
149         EditEngine *pEditEngine = pEditView->GetEditEngine();
150         if (pEditEngine)
151         {
152             pEditEngine->SetStatusEventHdl( Link() );
153             pEditEngine->RemoveView( pEditView );
154         }
155     }
156     delete pEditView;
157     delete pHScrollBar;
158     delete pVScrollBar;
159     delete pScrollBox;
160 }
161 
162 void SmEditWindow::InvalidateSlots()
163 {
164     SfxBindings& rBind = GetView()->GetViewFrame()->GetBindings();
165     rBind.Invalidate(SID_COPY);
166     rBind.Invalidate(SID_CUT);
167     rBind.Invalidate(SID_DELETE);
168 }
169 
170 SmViewShell * SmEditWindow::GetView()
171 {
172     return rCmdBox.GetView();
173 }
174 
175 
176 SmDocShell * SmEditWindow::GetDoc()
177 {
178     SmViewShell *pView = rCmdBox.GetView();
179     return pView ? pView->GetDoc() : 0;
180 }
181 
182 
183 EditEngine * SmEditWindow::GetEditEngine()
184 {
185     EditEngine *pEditEng = 0;
186     if (pEditView)
187         pEditEng = pEditView->GetEditEngine();
188     else
189     {
190         SmDocShell *pDoc = GetDoc();
191         if (pDoc)
192             pEditEng = &pDoc->GetEditEngine();
193     }
194     return pEditEng;
195 }
196 
197 
198 SfxItemPool * SmEditWindow::GetEditEngineItemPool()
199 {
200     SmDocShell *pDoc = GetDoc();
201     return pDoc ? &pDoc->GetEditEngineItemPool() : 0;
202 }
203 
204 void SmEditWindow::ApplyColorConfigValues( const svtools::ColorConfig &rColorCfg )
205 {
206     // Note: SetBackground still done in SmEditWindow::DataChanged
207 #if OSL_DEBUG_LEVEL > 1
208 //   ColorData nVal = rColorCfg.GetColorValue(svtools::FONTCOLOR).nColor;
209 #endif
210     SetTextColor( rColorCfg.GetColorValue(svtools::FONTCOLOR).nColor );
211     Invalidate();
212 }
213 
214 void SmEditWindow::DataChanged( const DataChangedEvent& )
215 {
216     const StyleSettings aSettings( GetSettings().GetStyleSettings() );
217 
218     ApplyColorConfigValues( SM_MOD()->GetColorConfig() );
219     SetBackground( aSettings.GetWindowColor() );
220 
221     // edit fields in other Applications use this font instead of
222     // the application font thus we use this one too
223     SetPointFont( aSettings.GetFieldFont() /*aSettings.GetAppFont()*/ );
224 
225     EditEngine  *pEditEngine = GetEditEngine();
226     SfxItemPool *pEditEngineItemPool = GetEditEngineItemPool();
227 
228     if (pEditEngine && pEditEngineItemPool)
229     {
230         //!
231         //! see also SmDocShell::GetEditEngine() !
232         //!
233 
234         pEditEngine->SetDefTab( sal_uInt16( GetTextWidth( C2S("XXXX") ) ) );
235 
236         SetEditEngineDefaultFonts( *pEditEngine, *pEditEngineItemPool );
237 
238         // forces new settings to be used
239         // unfortunately this resets the whole edit engine
240         // thus we need to save at least the text
241         String aTxt( pEditEngine->GetText( LINEEND_LF ) );
242         pEditEngine->Clear();   //#77957 incorrect font size
243         pEditEngine->SetText( aTxt );
244     }
245 
246     AdjustScrollBars();
247     Resize();
248 }
249 
250 IMPL_LINK( SmEditWindow, ModifyTimerHdl, Timer *, EMPTYARG /*pTimer*/ )
251 {
252     SmModule *pp = SM_MOD();
253     if (pp->GetConfig()->IsAutoRedraw())
254         Flush();
255     aModifyTimer.Stop();
256     return 0;
257 }
258 
259 
260 IMPL_LINK(SmEditWindow, CursorMoveTimerHdl, Timer *, EMPTYARG /*pTimer*/)
261     // every once in a while check cursor position (selection) of edit
262     // window and if it has changed (try to) set the formula-cursor
263     // according to that.
264 {
265     ESelection  aNewSelection   (GetSelection());
266 
267     if (!aNewSelection.IsEqual(aOldSelection))
268     {   SmViewShell *pView = rCmdBox.GetView();
269 
270         if (pView)
271         {
272             // get row and column to look for
273             sal_uInt16  nRow, nCol;
274             SmGetLeftSelectionPart(aNewSelection, nRow, nCol);
275             nRow++;
276             nCol++;
277 
278             pView->GetGraphicWindow().SetCursorPos(nRow, nCol);
279 
280             aOldSelection = aNewSelection;
281         }
282     }
283     aCursorMoveTimer.Stop();
284 
285     return 0;
286 }
287 
288 
289 void SmEditWindow::Resize()
290 {
291     if (!pEditView)
292         CreateEditView();
293 
294     if (pEditView)
295     {
296         pEditView->SetOutputArea(AdjustScrollBars());
297         pEditView->ShowCursor();
298 
299         DBG_ASSERT( pEditView->GetEditEngine(), "EditEngine missing" );
300         const long nMaxVisAreaStart = pEditView->GetEditEngine()->GetTextHeight() -
301                                       pEditView->GetOutputArea().GetHeight();
302         if (pEditView->GetVisArea().Top() > nMaxVisAreaStart)
303         {
304             Rectangle aVisArea(pEditView->GetVisArea() );
305             aVisArea.Top() = (nMaxVisAreaStart > 0 ) ? nMaxVisAreaStart : 0;
306             aVisArea.SetSize(pEditView->GetOutputArea().GetSize());
307             pEditView->SetVisArea(aVisArea);
308             pEditView->ShowCursor();
309         }
310         InitScrollBars();
311     }
312     Invalidate();
313 }
314 
315 void SmEditWindow::MouseButtonUp(const MouseEvent &rEvt)
316 {
317     if (pEditView)
318         pEditView->MouseButtonUp(rEvt);
319     else
320         Window::MouseButtonUp (rEvt);
321 
322     // ggf FormulaCursor neu positionieren
323     CursorMoveTimerHdl(&aCursorMoveTimer);
324     InvalidateSlots();
325 }
326 
327 void SmEditWindow::MouseButtonDown(const MouseEvent &rEvt)
328 {
329     if (pEditView)
330         pEditView->MouseButtonDown(rEvt);
331     else
332         Window::MouseButtonDown (rEvt);
333 
334     GrabFocus();
335 }
336 
337 void SmEditWindow::Command(const CommandEvent& rCEvt)
338 {
339     sal_Bool bForwardEvt = sal_True;
340     if (rCEvt.GetCommand() == COMMAND_CONTEXTMENU)
341     {
342         GetParent()->ToTop();
343 
344         Point aPoint = rCEvt.GetMousePosPixel();
345         PopupMenu* pPopupMenu = new PopupMenu(SmResId(RID_COMMANDMENU));
346 
347         // added for replaceability of context menus #96085, #93782
348         Menu* pMenu = NULL;
349         ::com::sun::star::ui::ContextMenuExecuteEvent aEvent;
350         aEvent.SourceWindow = VCLUnoHelper::GetInterface( this );
351         aEvent.ExecutePosition.X = aPoint.X();
352         aEvent.ExecutePosition.Y = aPoint.Y();
353         ::rtl::OUString sDummy;
354         if ( GetView()->TryContextMenuInterception( *pPopupMenu, sDummy, pMenu, aEvent ) )
355         {
356             if ( pMenu )
357             {
358                 delete pPopupMenu;
359                 pPopupMenu = (PopupMenu*) pMenu;
360             }
361         }
362 
363         pPopupMenu->SetSelectHdl(LINK(this, SmEditWindow, MenuSelectHdl));
364 
365         pPopupMenu->Execute( this, aPoint );
366         delete pPopupMenu;
367         bForwardEvt = sal_False;
368     }
369     else if (rCEvt.GetCommand() == COMMAND_WHEEL)
370         bForwardEvt = !HandleWheelCommands( rCEvt );
371 
372     if (bForwardEvt)
373     {
374         if (pEditView)
375             pEditView->Command( rCEvt );
376         else
377             Window::Command (rCEvt);
378     }
379 }
380 
381 
382 sal_Bool SmEditWindow::HandleWheelCommands( const CommandEvent &rCEvt )
383 {
384     sal_Bool bCommandHandled = sal_False;    // true if the CommandEvent needs not
385                                     // to be passed on (because it has fully
386                                     // been taken care of).
387 
388     const CommandWheelData* pWData = rCEvt.GetWheelData();
389     if (pWData)
390     {
391         if (COMMAND_WHEEL_ZOOM == pWData->GetMode())
392             bCommandHandled = sal_True;     // no zooming in Command window
393         else
394             bCommandHandled = HandleScrollCommand( rCEvt, pHScrollBar, pVScrollBar);
395     }
396 
397     return bCommandHandled;
398 }
399 
400 
401 IMPL_LINK_INLINE_START( SmEditWindow, MenuSelectHdl, Menu *, pMenu )
402 {
403     SmViewShell *pViewSh = rCmdBox.GetView();
404     if (pViewSh)
405         pViewSh->GetViewFrame()->GetDispatcher()->Execute(
406                 SID_INSERTCOMMAND, SFX_CALLMODE_STANDARD,
407                 new SfxInt16Item(SID_INSERTCOMMAND, pMenu->GetCurItemId()), 0L);
408     return 0;
409 }
410 IMPL_LINK_INLINE_END( SmEditWindow, MenuSelectHdl, Menu *, pMenu )
411 
412 void SmEditWindow::KeyInput(const KeyEvent& rKEvt)
413 {
414     if (rKEvt.GetKeyCode().GetCode() == KEY_ESCAPE)
415     {
416         sal_Bool bCallBase = sal_True;
417         SfxViewShell* pViewShell = GetView();
418         if ( pViewShell && pViewShell->ISA(SmViewShell) )
419         {
420             // Terminate possible InPlace mode
421             bCallBase = !pViewShell->Escape();
422         }
423         if ( bCallBase )
424             Window::KeyInput( rKEvt );
425     }
426     else
427     {
428         // Timer neu starten, um den Handler (auch bei laengeren Eingaben)
429         // moeglichst nur einmal am Ende aufzurufen.
430         aCursorMoveTimer.Start();
431 
432         DBG_ASSERT( pEditView, "EditView missing (NULL pointer)" );
433         if (!pEditView)
434             CreateEditView();
435         if ( !pEditView->PostKeyEvent(rKEvt) )
436         {
437             SmViewShell *pView = GetView();
438             if ( pView && !pView->KeyInput(rKEvt) )
439             {
440                 /* fuert bei F1 (Hilfe) zum Zerstoeren von this! */
441                 Flush();
442                 if ( aModifyTimer.IsActive() )
443                     aModifyTimer.Stop();
444                 Window::KeyInput(rKEvt);
445             }
446             else
447             {
448                 //SFX hat evtl. Slot an der View gecallt und dabei (wg. Hack
449                 //im SFX) den Focus auf die View gesetzt
450                 SfxViewShell* pVShell = GetView();
451                 if ( pVShell && pVShell->ISA(SmViewShell) &&
452                      ((SmViewShell*)pVShell)->GetGraphicWindow().HasFocus() )
453                 {
454                     GrabFocus();
455                 }
456             }
457         }
458         else
459         {
460             // have doc-shell modified only for formula input/change and not
461             // cursor travelling and such things...
462             SmDocShell *pDocShell = GetDoc();
463             if (pDocShell)
464                 pDocShell->SetModified( GetEditEngine()->IsModified() );
465 
466             aModifyTimer.Start();
467         }
468 
469         InvalidateSlots();
470     }
471 }
472 
473 void SmEditWindow::Paint(const Rectangle& rRect)
474 {
475     if (!pEditView)
476         CreateEditView();
477     pEditView->Paint(rRect);
478 }
479 
480 void SmEditWindow::CreateEditView()
481 {
482     EditEngine *pEditEngine = GetEditEngine();
483 
484     //! pEditEngine and pEditView may be 0.
485     //! For example when the program is used by the document-converter
486     if (!pEditView && pEditEngine)
487     {
488         pEditView = new EditView( pEditEngine, this );
489         pEditEngine->InsertView( pEditView );
490 
491         if (!pVScrollBar)
492             pVScrollBar = new ScrollBar(this, WinBits(WB_VSCROLL));
493         if (!pHScrollBar)
494             pHScrollBar = new ScrollBar(this, WinBits(WB_HSCROLL));
495         if (!pScrollBox)
496             pScrollBox  = new ScrollBarBox(this);
497         pVScrollBar->SetScrollHdl(LINK(this, SmEditWindow, ScrollHdl));
498         pHScrollBar->SetScrollHdl(LINK(this, SmEditWindow, ScrollHdl));
499         pVScrollBar->EnableDrag( sal_True );
500         pHScrollBar->EnableDrag( sal_True );
501 
502         pEditView->SetOutputArea(AdjustScrollBars());
503 
504         ESelection eSelection;
505 
506         pEditView->SetSelection(eSelection);
507         Update();
508         pEditView->ShowCursor(sal_True, sal_True);
509 
510         pEditEngine->SetStatusEventHdl( LINK(this, SmEditWindow, EditStatusHdl) );
511         SetPointer(pEditView->GetPointer());
512 
513         SetScrollBarRanges();
514     }
515 }
516 
517 
518 IMPL_LINK( SmEditWindow, EditStatusHdl, EditStatus *, EMPTYARG /*pStat*/ )
519 {
520     if (!pEditView)
521         return 1;
522     else
523     {
524         Resize();
525         return 0;
526     }
527 }
528 
529 IMPL_LINK_INLINE_START( SmEditWindow, ScrollHdl, ScrollBar *, EMPTYARG /*pScrollBar*/ )
530 {
531     DBG_ASSERT(pEditView, "EditView missing");
532     if (pEditView)
533     {
534         pEditView->SetVisArea(Rectangle(Point(pHScrollBar->GetThumbPos(),
535                                             pVScrollBar->GetThumbPos()),
536                                         pEditView->GetVisArea().GetSize()));
537         pEditView->Invalidate();
538     }
539     return 0;
540 }
541 IMPL_LINK_INLINE_END( SmEditWindow, ScrollHdl, ScrollBar *, pScrollBar )
542 
543 Rectangle SmEditWindow::AdjustScrollBars()
544 {
545     const Size aOut( GetOutputSizePixel() );
546     Point aPoint;
547     Rectangle aRect( aPoint, aOut );
548 
549     if (pVScrollBar && pHScrollBar && pScrollBox)
550     {
551         const long nTmp = GetSettings().GetStyleSettings().GetScrollBarSize();
552         Point aPt( aRect.TopRight() ); aPt.X() -= nTmp -1L;
553         pVScrollBar->SetPosSizePixel( aPt, Size(nTmp, aOut.Height() - nTmp));
554 
555         aPt = aRect.BottomLeft(); aPt.Y() -= nTmp - 1L;
556         pHScrollBar->SetPosSizePixel( aPt, Size(aOut.Width() - nTmp, nTmp));
557 
558         aPt.X() = pHScrollBar->GetSizePixel().Width();
559         aPt.Y() = pVScrollBar->GetSizePixel().Height();
560         pScrollBox->SetPosSizePixel(aPt, Size(nTmp, nTmp ));
561 
562         aRect.Right()  = aPt.X() - 2;
563         aRect.Bottom() = aPt.Y() - 2;
564     }
565     return aRect;
566 }
567 
568 void SmEditWindow::SetScrollBarRanges()
569 {
570     // Extra-Methode, nicht InitScrollBars, da auch fuer EditEngine-Events.
571     EditEngine *pEditEngine = GetEditEngine();
572     if (pVScrollBar && pHScrollBar && pEditEngine && pEditView)
573     {
574         long nTmp = pEditEngine->GetTextHeight();
575         pVScrollBar->SetRange(Range(0, nTmp));
576         pVScrollBar->SetThumbPos(pEditView->GetVisArea().Top());
577 
578         nTmp = pEditEngine->GetPaperSize().Width();
579         pHScrollBar->SetRange(Range(0,nTmp));
580         pHScrollBar->SetThumbPos(pEditView->GetVisArea().Left());
581     }
582 }
583 
584 void SmEditWindow::InitScrollBars()
585 {
586     if (pVScrollBar && pHScrollBar && pScrollBox && pEditView)
587     {
588         const Size aOut( pEditView->GetOutputArea().GetSize() );
589         pVScrollBar->SetVisibleSize(aOut.Height());
590         pVScrollBar->SetPageSize(aOut.Height() * 8 / 10);
591         pVScrollBar->SetLineSize(aOut.Height() * 2 / 10);
592 
593         pHScrollBar->SetVisibleSize(aOut.Width());
594         pHScrollBar->SetPageSize(aOut.Width() * 8 / 10);
595         pHScrollBar->SetLineSize(SCROLL_LINE );
596 
597         SetScrollBarRanges();
598 
599         pVScrollBar->Show();
600         pHScrollBar->Show();
601         pScrollBox->Show();
602     }
603 }
604 
605 
606 String SmEditWindow::GetText() const
607 {
608     String aText;
609     EditEngine *pEditEngine = const_cast< SmEditWindow* >(this)->GetEditEngine();
610     DBG_ASSERT( pEditEngine, "EditEngine missing" );
611     if (pEditEngine)
612         aText = pEditEngine->GetText( LINEEND_LF );
613     return aText;
614 }
615 
616 
617 void SmEditWindow::SetText(const XubString& rText)
618 {
619     EditEngine *pEditEngine = GetEditEngine();
620     DBG_ASSERT( pEditEngine, "EditEngine missing" );
621     if (pEditEngine  &&  !pEditEngine->IsModified())
622     {
623         if (!pEditView)
624             CreateEditView();
625 
626         ESelection eSelection = pEditView->GetSelection();
627 
628         pEditEngine->SetText(rText);
629         pEditEngine->ClearModifyFlag();
630 
631         //! Hier die Timer neu zu starten verhindert, dass die Handler fuer andere
632         //! (im Augenblick nicht mehr aktive) Math Tasks aufgerufen werden.
633         aModifyTimer.Start();
634         aCursorMoveTimer.Start();
635 
636         pEditView->SetSelection(eSelection);
637     }
638 }
639 
640 
641 void SmEditWindow::GetFocus()
642 {
643     Window::GetFocus();
644 
645     if (xAccessible.is())
646     {
647         // Note: will implicitly send the AccessibleStateType::FOCUSED event
648         ::accessibility::AccessibleTextHelper *pHelper = pAccessible->GetTextHelper();
649         if (pHelper)
650             pHelper->SetFocus( sal_True );
651     }
652 
653     if (!pEditView)
654          CreateEditView();
655     EditEngine *pEditEngine = GetEditEngine();
656     if (pEditEngine)
657         pEditEngine->SetStatusEventHdl( LINK(this, SmEditWindow, EditStatusHdl) );
658 }
659 
660 
661 void SmEditWindow::LoseFocus()
662 {
663     EditEngine *pEditEngine = GetEditEngine();
664     if (pEditEngine)
665         pEditEngine->SetStatusEventHdl( Link() );
666 
667     Window::LoseFocus();
668 
669     if (xAccessible.is())
670     {
671         // Note: will implicitly send the AccessibleStateType::FOCUSED event
672         ::accessibility::AccessibleTextHelper *pHelper = pAccessible->GetTextHelper();
673         if (pHelper)
674             pHelper->SetFocus( sal_False );
675     }
676 }
677 
678 
679 sal_Bool SmEditWindow::IsAllSelected() const
680 {
681     sal_Bool bRes = sal_False;
682     EditEngine *pEditEngine = ((SmEditWindow *) this)->GetEditEngine();
683     DBG_ASSERT( pEditView, "NULL pointer" );
684     DBG_ASSERT( pEditEngine, "NULL pointer" );
685     if (pEditEngine  &&  pEditView)
686     {
687         ESelection eSelection( pEditView->GetSelection() );
688         sal_Int32 nParaCnt = pEditEngine->GetParagraphCount();
689         if (!(nParaCnt - 1))
690         {
691             String Text( pEditEngine->GetText( LINEEND_LF ) );
692             bRes = !eSelection.nStartPos && (eSelection.nEndPos == Text.Len () - 1);
693         }
694         else
695         {
696             bRes = !eSelection.nStartPara && (eSelection.nEndPara == nParaCnt - 1);
697         }
698     }
699     return bRes;
700 }
701 
702 void SmEditWindow::SelectAll()
703 {
704     DBG_ASSERT( pEditView, "NULL pointer" );
705     if (pEditView)
706     {
707         // 0xFFFF as last two parameters refers to the end of the text
708         pEditView->SetSelection( ESelection( 0, 0, 0xFFFF, 0xFFFF ) );
709     }
710 }
711 
712 void SmEditWindow::InsertCommand(sal_uInt16 nCommand)
713 {
714     DBG_ASSERT( pEditView, "EditView missing" );
715     if (pEditView)
716     {
717         //Anfang der Selektion merken und hinterher den Cursor daraufsetzen. Nur so
718         //macht das SelNextMark() Sinn.
719         ESelection aSelection = pEditView->GetSelection();
720         aSelection.nEndPos  = aSelection.nStartPos;
721         aSelection.nEndPara = aSelection.nStartPara;
722 
723         DBG_ASSERT( pEditView, "NULL pointer" );
724         String  aText = String(SmResId(nCommand));
725         pEditView->InsertText(aText);
726 
727         if (HasMark(aText))
728         {   // set selection to next mark
729             pEditView->SetSelection(aSelection);
730             SelNextMark();
731         }
732         else
733         {   // set selection after inserted text
734             aSelection.nEndPos    = aSelection.nEndPos + sal::static_int_cast< xub_StrLen >(aText.Len());
735             aSelection.nStartPos  = aSelection.nEndPos;
736             pEditView->SetSelection(aSelection);
737         }
738 
739         aModifyTimer.Start();
740         aCursorMoveTimer.Start();
741 
742         GrabFocus();
743     }
744 }
745 
746 void SmEditWindow::MarkError(const Point &rPos)
747 {
748     DBG_ASSERT( pEditView, "EditView missing" );
749     if (pEditView)
750     {
751         const xub_StrLen    nCol = sal::static_int_cast< xub_StrLen >(rPos.X());
752         const sal_uInt16        nRow = sal::static_int_cast< sal_uInt16 >(rPos.Y() - 1);
753 
754         pEditView->SetSelection(ESelection(nRow, nCol - 1, nRow, nCol));
755         GrabFocus();
756     }
757 }
758 
759 void SmEditWindow::SelNextMark()
760 {
761     EditEngine *pEditEngine = GetEditEngine();
762     DBG_ASSERT( pEditView, "NULL pointer" );
763     DBG_ASSERT( pEditEngine, "NULL pointer" );
764     if (pEditEngine  &&  pEditView)
765     {
766         ESelection eSelection = pEditView->GetSelection();
767         sal_uInt16     Pos        = eSelection.nEndPos;
768         String     aMark (C2S("<?>"));
769         String     aText;
770         sal_uInt16     nCounts    = pEditEngine->GetParagraphCount();
771 
772         while (eSelection.nEndPara < nCounts)
773         {
774             aText = pEditEngine->GetText( eSelection.nEndPara );
775             Pos   = aText.Search(aMark, Pos);
776 
777             if (Pos != STRING_NOTFOUND)
778             {
779                 pEditView->SetSelection(ESelection (eSelection.nEndPara, Pos, eSelection.nEndPara, Pos + 3));
780                 break;
781             }
782 
783             Pos = 0;
784             eSelection.nEndPara++;
785         }
786     }
787 }
788 
789 void SmEditWindow::SelPrevMark()
790 {
791     EditEngine *pEditEngine = GetEditEngine();
792     DBG_ASSERT( pEditEngine, "NULL pointer" );
793     DBG_ASSERT( pEditView, "NULL pointer" );
794     if (pEditEngine  &&  pEditView)
795     {
796         ESelection eSelection = pEditView->GetSelection();
797         sal_uInt16     Pos        = STRING_NOTFOUND;
798         xub_StrLen Max        = eSelection.nStartPos;
799         String     Text( pEditEngine->GetText( eSelection.nStartPara ) );
800         String     aMark (C2S("<?>"));
801         sal_uInt16     nCounts    = pEditEngine->GetParagraphCount();
802 
803         do
804         {
805             sal_uInt16 Fnd = Text.Search(aMark, 0);
806 
807             while ((Fnd < Max) && (Fnd != STRING_NOTFOUND))
808             {
809                 Pos = Fnd;
810                 Fnd = Text.Search(aMark, Fnd + 1);
811             }
812 
813             if (Pos == STRING_NOTFOUND)
814             {
815                 eSelection.nStartPara--;
816                 Text = pEditEngine->GetText( eSelection.nStartPara );
817                 Max = Text.Len();
818             }
819         }
820         while ((eSelection.nStartPara < nCounts) &&
821             (Pos == STRING_NOTFOUND));
822 
823         if (Pos != STRING_NOTFOUND)
824         {
825             pEditView->SetSelection(ESelection (eSelection.nStartPara, Pos, eSelection.nStartPara, Pos + 3));
826         }
827     }
828 }
829 
830 sal_Bool SmEditWindow::HasMark(const String& rText) const
831     // returns true iff 'rText' contains a mark
832 {
833     return rText.SearchAscii("<?>", 0) != STRING_NOTFOUND;
834 }
835 
836 void SmEditWindow::MouseMove(const MouseEvent &rEvt)
837 {
838     if (pEditView)
839         pEditView->MouseMove(rEvt);
840 }
841 
842 sal_Int8 SmEditWindow::AcceptDrop( const AcceptDropEvent& /*rEvt*/ )
843 {
844     return pEditView ? /*pEditView->QueryDrop( rEvt )*/DND_ACTION_NONE: DND_ACTION_NONE;
845 }
846 
847 sal_Int8 SmEditWindow::ExecuteDrop( const ExecuteDropEvent& /*rEvt*/ )
848 {
849     return pEditView ? /*pEditView->Drop( rEvt )*/DND_ACTION_NONE : DND_ACTION_NONE;
850 }
851 
852 ESelection SmEditWindow::GetSelection() const
853 {
854     // pointer may be 0 when reloading a document and the old view
855     // was already destroyed
856     //(DBG_ASSERT( pEditView, "NULL pointer" );
857     ESelection eSel;
858     if (pEditView)
859         eSel = pEditView->GetSelection();
860     return eSel;
861 }
862 
863 void SmEditWindow::SetSelection(const ESelection &rSel)
864 {
865     DBG_ASSERT( pEditView, "NULL pointer" );
866     if (pEditView)
867         pEditView->SetSelection(rSel);
868     InvalidateSlots();
869 }
870 
871 sal_Bool SmEditWindow::IsEmpty() const
872 {
873     EditEngine *pEditEngine = ((SmEditWindow *) this)->GetEditEngine();
874     sal_Bool bEmpty = sal::static_int_cast< sal_Bool >(
875                     pEditEngine ? pEditEngine->GetTextLen() == 0 : sal_False);
876     return bEmpty;
877 }
878 
879 sal_Bool SmEditWindow::IsSelected() const
880 {
881     return pEditView ? pEditView->HasSelection() : sal_False;
882 }
883 
884 void SmEditWindow::Cut()
885 {
886     DBG_ASSERT( pEditView, "EditView missing" );
887     if (pEditView)
888     {
889         pEditView->Cut();
890         GetDoc()->SetModified( sal_True );
891     }
892 }
893 
894 void SmEditWindow::Copy()
895 {
896     DBG_ASSERT( pEditView, "EditView missing" );
897     if (pEditView)
898         pEditView->Copy();
899 }
900 
901 void SmEditWindow::Paste()
902 {
903     DBG_ASSERT( pEditView, "EditView missing" );
904     if (pEditView)
905     {
906         pEditView->Paste();
907         GetDoc()->SetModified( sal_True );
908     }
909 }
910 
911 void SmEditWindow::Delete()
912 {
913     DBG_ASSERT( pEditView, "EditView missing" );
914     if (pEditView)
915     {
916         pEditView->DeleteSelected();
917         GetDoc()->SetModified( sal_True );
918     }
919 }
920 
921 void SmEditWindow::InsertText(const String& Text)
922 {
923     DBG_ASSERT( pEditView, "EditView missing" );
924     if (pEditView)
925     {
926         pEditView->InsertText(Text);
927         aModifyTimer.Start();
928         aCursorMoveTimer.Start();
929     }
930 }
931 
932 void SmEditWindow::Flush()
933 {
934     EditEngine *pEditEngine = GetEditEngine();
935     if (pEditEngine  &&  pEditEngine->IsModified())
936     {
937         pEditEngine->ClearModifyFlag();
938         SmViewShell *pViewSh = rCmdBox.GetView();
939         if (pViewSh)
940         {
941             pViewSh->GetViewFrame()->GetDispatcher()->Execute(
942                     SID_TEXT, SFX_CALLMODE_STANDARD,
943                     new SfxStringItem(SID_TEXT, GetText()), 0L);
944         }
945     }
946 
947     if (aCursorMoveTimer.IsActive())
948     {
949         aCursorMoveTimer.Stop();
950         // ggf noch die (neue) FormulaCursor Position setzen
951         CursorMoveTimerHdl(&aCursorMoveTimer);
952     }
953 }
954 
955 
956 void SmEditWindow::DeleteEditView( SmViewShell & /*rView*/ )
957 {
958     if (pEditView)
959     {
960         EditEngine *pEditEngine = pEditView->GetEditEngine();
961         if (pEditEngine)
962         {
963             pEditEngine->SetStatusEventHdl( Link() );
964             pEditEngine->RemoveView( pEditView );
965         }
966         delete pEditView;
967         pEditView = 0;
968     }
969 }
970 
971 
972 uno::Reference< XAccessible > SmEditWindow::CreateAccessible()
973 {
974     if (!pAccessible)
975     {
976         pAccessible = new SmEditAccessible( this );
977         xAccessible = pAccessible;
978         pAccessible->Init();
979     }
980     return xAccessible;
981 }
982 
983