xref: /aoo41x/main/starmath/source/edit.cxx (revision cdf0e10c)
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